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_inputPickerType(-1)
99 , m_doNotHandleFakeKeyEvent(false)
100 , m_fakeKeyEventTimer(this, &InputMethodContextEfl::fakeKeyEventTimerFired)
101 , m_approximateCursorPosition(0)
102 , m_isLastKeyEventFiltered(false)
105 #if ENABLE(TIZEN_ISF_PORT)
106 if (!s_externalKeyboardProperty)
107 initializeExternalKeyboard();
110 ecore_imf_context_event_callback_add(m_context.get(), ECORE_IMF_CALLBACK_PREEDIT_CHANGED, onIMFPreeditSequenceChanged, this);
111 ecore_imf_context_event_callback_add(m_context.get(), ECORE_IMF_CALLBACK_COMMIT, onIMFInputSequenceComplete, this);
115 InputMethodContextEfl::~InputMethodContextEfl()
119 #if ENABLE(TIZEN_ISF_PORT)
120 void InputMethodContextEfl::onIMFInputPanelStateChanged(void* data, Ecore_IMF_Context*, int state)
122 InputMethodContextEfl* inputMethodContext = static_cast<InputMethodContextEfl*>(data);
124 inputMethodContext->setState(state);
126 if (state == ECORE_IMF_INPUT_PANEL_STATE_HIDE) {
127 #if ENABLE(TIZEN_WEBKIT2_CONTEXT_MENU_CLIPBOARD)
128 if (!s_shouldUseExternalKeyboard && inputMethodContext->m_viewImpl->pageClient->isClipboardWindowOpened())
129 inputMethodContext->m_viewImpl->pageClient->closeClipboardWindow();
132 if (inputMethodContext->m_viewImpl->page()->editorState().hasComposition)
133 inputMethodContext->resetIMFContext();
135 evas_object_smart_callback_call(inputMethodContext->m_viewImpl->view(), "editorclient,ime,closed", 0);
136 } else if (state == ECORE_IMF_INPUT_PANEL_STATE_SHOW)
137 evas_object_smart_callback_call(inputMethodContext->m_viewImpl->view(), "editorclient,ime,opened", 0);
140 void InputMethodContextEfl::onIMFInputPanelGeometryChanged(void* data, Ecore_IMF_Context*, int)
142 InputMethodContextEfl* inputMethodContext = static_cast<InputMethodContextEfl*>(data);
143 if (!inputMethodContext->m_context)
147 ecore_imf_context_input_panel_geometry_get(inputMethodContext->m_context.get(), &rect.x, &rect.y, &rect.w, &rect.h);
148 evas_object_smart_callback_call(inputMethodContext->m_viewImpl->view(), "inputmethod,changed", &rect);
150 inputMethodContext->setIMERect(IntRect(rect.x, rect.y, rect.w, rect.h));
153 void InputMethodContextEfl::onIMFCandidatePanelStateChanged(void* data, Ecore_IMF_Context*, int state)
155 InputMethodContextEfl* inputMethodContext = static_cast<InputMethodContextEfl*>(data);
157 if (state == ECORE_IMF_CANDIDATE_PANEL_SHOW)
158 evas_object_smart_callback_call(inputMethodContext->m_viewImpl->view(), "editorclient,candidate,opened", 0);
160 evas_object_smart_callback_call(inputMethodContext->m_viewImpl->view(), "editorclient,candidate,closed", 0);
163 void InputMethodContextEfl::onIMFCandidatePanelGeometryChanged(void* data, Ecore_IMF_Context*, int)
165 InputMethodContextEfl* inputMethodContext = static_cast<InputMethodContextEfl*>(data);
166 if (!inputMethodContext->m_context)
170 ecore_imf_context_candidate_panel_geometry_get(inputMethodContext->m_context.get(), &rect.x, &rect.y, &rect.w, &rect.h);
171 evas_object_smart_callback_call(inputMethodContext->m_viewImpl->view(), "editorclient,candidate,changed", &rect);
174 Eina_Bool InputMethodContextEfl::onIMFRetrieveSurrounding(void* data, Ecore_IMF_Context*, char** text, int* offset)
176 InputMethodContextEfl* inputMethodContext = static_cast<InputMethodContextEfl*>(data);
177 if (!inputMethodContext->m_viewImpl->page()->focusedFrame() || !inputMethodContext->m_focused || (!text && !offset))
180 const EditorState& editor = inputMethodContext->m_viewImpl->page()->editorState();
184 if (!inputMethodContext->m_approximateSurroundingText.isNull())
185 utf8Text = inputMethodContext->m_approximateSurroundingText.utf8();
187 utf8Text = editor.surroundingText.utf8();
188 size_t length = utf8Text.length();
190 *text = static_cast<char*>(malloc((length + 1) * sizeof(char)));
195 strncpy(*text, utf8Text.data(), length);
200 if (!inputMethodContext->m_approximateSurroundingText.isNull())
201 *offset = inputMethodContext->m_approximateCursorPosition;
203 *offset = editor.cursorPosition;
209 void InputMethodContextEfl::onIMFDeleteSurrounding(void* data, Ecore_IMF_Context*, void* eventInfo)
211 InputMethodContextEfl* inputMethodContext = static_cast<InputMethodContextEfl*>(data);
212 if (!eventInfo || !inputMethodContext->m_viewImpl->page()->focusedFrame() || !inputMethodContext->m_focused)
215 inputMethodContext->requestFakeKeyEvent();
217 Ecore_IMF_Event_Delete_Surrounding* event = static_cast<Ecore_IMF_Event_Delete_Surrounding*>(eventInfo);
218 inputMethodContext->m_viewImpl->page()->deleteSurroundingText(event->offset, event->n_chars);
220 inputMethodContext->updateApproximateText(String(), event->offset, event->n_chars);
223 void InputMethodContextEfl::onIMFInputSequenceComplete(void* data, Ecore_IMF_Context*, void* eventInfo)
225 InputMethodContextEfl* inputMethodContext = static_cast<InputMethodContextEfl*>(data);
226 if (!eventInfo || !inputMethodContext->m_focused)
229 inputMethodContext->requestFakeKeyEvent();
231 String completeString = String::fromUTF8(static_cast<char*>(eventInfo));
232 inputMethodContext->m_viewImpl->page()->confirmComposition(completeString);
234 inputMethodContext->updateApproximateText(completeString, 0, 0);
237 #if ENABLE(TIZEN_WEBKIT2_SUPPORT_JAPANESE_IME)
238 unsigned getUTF8CharacterIndex(const char* string, unsigned byteIndex)
241 const char* end = string + byteIndex;
243 while (*string && string < end) {
246 if ((*string & 0x80) == 0x00)
248 else if ((*string & 0xe0) == 0xc0)
250 else if ((*string & 0xf0) == 0xe0)
252 else if ((*string & 0xf8) == 0xf0)
254 else if ((*string & 0xfc) == 0xf8)
256 else if ((*string & 0xfe) == 0xfc)
262 while (*string && offset--)
270 void InputMethodContextEfl::onIMFPreeditSequenceChanged(void* data, Ecore_IMF_Context* context, void*)
272 InputMethodContextEfl* inputMethodContext = static_cast<InputMethodContextEfl*>(data);
274 if (!inputMethodContext->m_viewImpl->page()->focusedFrame() || !inputMethodContext->m_focused)
277 WebPageProxy* page = inputMethodContext->m_viewImpl->page();
278 if (!page->focusedFrame())
281 inputMethodContext->requestFakeKeyEvent();
283 const EditorState& editor = inputMethodContext->m_viewImpl->page()->editorState();
284 PageClientImpl* pageClient = inputMethodContext->m_viewImpl->pageClient.get();
286 if (!editor.selectionIsNone && !editor.selectionIsRange) {
287 caretRect = editor.selectionRect;
288 caretRect.scale(pageClient->scaleFactor());
292 evas_object_geometry_get(inputMethodContext->m_viewImpl->view(), &viewX, &viewY, 0, 0);
294 int x = caretRect.x() - pageClient->scrollPosition().x() + viewX;
295 int y = caretRect.y() - pageClient->scrollPosition().y() + viewY;
296 int w = caretRect.width();
297 int h = caretRect.height();
298 ecore_imf_context_cursor_location_set(context, x, y, w, h);
301 Eina_List* preeditAttrs = 0;
302 int cursorPosition = 0;
304 ecore_imf_context_preedit_string_with_attributes_get(context, &buffer, &preeditAttrs, &cursorPosition);
306 String preeditString = String::fromUTF8(buffer);
307 Vector<CompositionUnderline> underlines;
311 #if ENABLE(TIZEN_WEBKIT2_SUPPORT_JAPANESE_IME)
312 Eina_List* listIterator = 0;
313 EINA_LIST_FOREACH(preeditAttrs, listIterator, item) {
314 Ecore_IMF_Preedit_Attr* preeditAttr = static_cast<Ecore_IMF_Preedit_Attr*>(item);
316 unsigned startIndex = getUTF8CharacterIndex(buffer, preeditAttr->start_index);
317 unsigned endIndex = getUTF8CharacterIndex(buffer, preeditAttr->end_index);
318 switch (preeditAttr->preedit_type) {
319 case ECORE_IMF_PREEDIT_TYPE_SUB1:
320 underlines.append(CompositionUnderline(startIndex, endIndex, Color(0, 0, 0), false));
322 case ECORE_IMF_PREEDIT_TYPE_SUB2:
323 case ECORE_IMF_PREEDIT_TYPE_SUB3:
324 underlines.append(CompositionUnderline(startIndex, endIndex, Color(0, 0, 0), Color(255, 255, 255), false));
326 case ECORE_IMF_PREEDIT_TYPE_SUB4:
327 underlines.append(CompositionUnderline(startIndex, endIndex, Color(0, 0, 0), Color(46, 168, 255), false));
329 case ECORE_IMF_PREEDIT_TYPE_SUB5:
330 underlines.append(CompositionUnderline(startIndex, endIndex, Color(0, 0, 0), Color(153, 98, 195), false));
332 case ECORE_IMF_PREEDIT_TYPE_SUB6:
333 underlines.append(CompositionUnderline(startIndex, endIndex, Color(0, 0, 0), Color(118, 222, 55), false));
335 case ECORE_IMF_PREEDIT_TYPE_SUB7:
336 underlines.append(CompositionUnderline(startIndex, endIndex, Color(0, 0, 0), Color(153, 153, 153), false));
343 EINA_LIST_FREE(preeditAttrs, item)
347 if (underlines.isEmpty())
348 underlines.append(CompositionUnderline(0, preeditString.length(), Color(0, 0, 0), false));
350 page->setComposition(preeditString, underlines, cursorPosition);
355 inputMethodContext->updateApproximateText(preeditString, 0, 0);
358 void InputMethodContextEfl::onIMFInputSequenceComplete(void* data, Ecore_IMF_Context*, void* eventInfo)
360 InputMethodContextEfl* inputMethodContext = static_cast<InputMethodContextEfl*>(data);
361 if (!eventInfo || !inputMethodContext->m_focused)
364 inputMethodContext->m_viewImpl->page()->confirmComposition(String::fromUTF8(static_cast<char*>(eventInfo)));
367 void InputMethodContextEfl::onIMFPreeditSequenceChanged(void* data, Ecore_IMF_Context* context, void*)
369 InputMethodContextEfl* inputMethodContext = static_cast<InputMethodContextEfl*>(data);
371 if (!inputMethodContext->m_viewImpl->page()->focusedFrame() || !inputMethodContext->m_focused)
375 ecore_imf_context_preedit_string_get(context, &buffer, 0);
379 String preeditString = String::fromUTF8(buffer);
381 Vector<CompositionUnderline> underlines;
382 underlines.append(CompositionUnderline(0, preeditString.length(), Color(0, 0, 0), false));
383 inputMethodContext->m_viewImpl->page()->setComposition(preeditString, underlines, 0);
387 PassOwnPtr<Ecore_IMF_Context> InputMethodContextEfl::createIMFContext(Evas* canvas)
389 const char* defaultContextID = ecore_imf_context_default_id_get();
390 if (!defaultContextID)
393 OwnPtr<Ecore_IMF_Context> imfContext = adoptPtr(ecore_imf_context_add(defaultContextID));
397 Ecore_Evas* ecoreEvas = ecore_evas_ecore_evas_get(canvas);
398 ecore_imf_context_client_window_set(imfContext.get(), reinterpret_cast<void*>(ecore_evas_window_get(ecoreEvas)));
399 ecore_imf_context_client_canvas_set(imfContext.get(), canvas);
401 return imfContext.release();
404 void InputMethodContextEfl::handleMouseUpEvent(const Evas_Event_Mouse_Up*)
406 #if ENABLE(TIZEN_ISF_PORT)
412 ecore_imf_context_reset(m_context.get());
416 void InputMethodContextEfl::handleKeyDownEvent(const Evas_Event_Key_Down* downEvent, bool* isFiltered)
418 #if ENABLE(TIZEN_ISF_PORT)
422 const EditorState& state = m_viewImpl->page()->editorState();
424 if (!m_isLastKeyEventFiltered && !m_approximateSurroundingText.isNull() && !state.hasComposition)
425 ecore_imf_context_cursor_position_set(m_context.get(), m_approximateCursorPosition);
427 if (m_fakeKeyEventTimer.isActive())
428 m_fakeKeyEventTimer.stop();
430 m_viewImpl->page()->prepareKeyDownEvent();
432 m_doNotHandleFakeKeyEvent = true;
435 Ecore_IMF_Event inputMethodEvent;
436 ecore_imf_evas_event_key_down_wrap(const_cast<Evas_Event_Key_Down*>(downEvent), &inputMethodEvent.key_down);
438 *isFiltered = ecore_imf_context_filter_event(m_context.get(), ECORE_IMF_EVENT_KEY_DOWN, &inputMethodEvent);
440 #if ENABLE(TIZEN_ISF_PORT)
441 m_doNotHandleFakeKeyEvent = false;
442 m_isLastKeyEventFiltered = *isFiltered;
445 if (!strcmp(downEvent->key, "BackSpace")) {
446 if (state.cursorPosition > 0)
447 updateApproximateText(String(), state.cursorPosition - 1, 1);
448 } else if (!strcmp(downEvent->key, "Delete")) {
449 if (state.cursorPosition < state.surroundingText.length())
450 updateApproximateText(String(), state.cursorPosition, 1);
452 updateApproximateText(String::fromUTF8(downEvent->compose), 0, 0);
457 #if ENABLE(TIZEN_ISF_PORT)
458 void InputMethodContextEfl::updateTextInputState()
460 const EditorState& editor = m_viewImpl->page()->editorState();
461 if (editor.shouldIgnoreCompositionSelectionChange || editor.updateEditorRectOnly)
464 if (editor.isContentEditable)
465 showIMFContext(editor);
469 m_approximateSurroundingText = String();
471 if (m_context && !editor.hasComposition)
472 ecore_imf_context_cursor_position_set(m_context.get(), editor.cursorPosition);
475 void InputMethodContextEfl::updateTextInputStateByUserAction(bool setFocus)
477 const EditorState& editor = m_viewImpl->page()->editorState();
479 if (editor.isContentEditable) {
481 evas_object_focus_set(m_viewImpl->view(), true);
483 showIMFContext(editor, true);
488 void InputMethodContextEfl::updateTextInputState()
493 const EditorState& editor = m_viewImpl->page()->editorState();
495 if (editor.isContentEditable) {
499 ecore_imf_context_reset(m_context.get());
500 ecore_imf_context_focus_in(m_context.get());
506 if (editor.hasComposition)
507 m_viewImpl->page()->cancelComposition();
510 ecore_imf_context_reset(m_context.get());
511 ecore_imf_context_focus_out(m_context.get());
516 #if ENABLE(TIZEN_ISF_PORT)
517 void InputMethodContextEfl::initializeIMFContext(Ecore_IMF_Context* context, Ecore_IMF_Input_Panel_Layout layout, int layoutVariation, Ecore_IMF_Input_Panel_Return_Key_Type returnKeyType)
519 ecore_imf_context_input_panel_enabled_set(context, false);
520 ecore_imf_context_input_panel_event_callback_add(context, ECORE_IMF_INPUT_PANEL_STATE_EVENT, onIMFInputPanelStateChanged, this);
521 ecore_imf_context_input_panel_event_callback_add(context, ECORE_IMF_INPUT_PANEL_GEOMETRY_EVENT, onIMFInputPanelGeometryChanged, this);
522 ecore_imf_context_input_panel_event_callback_add(context, ECORE_IMF_CANDIDATE_PANEL_STATE_EVENT, onIMFCandidatePanelStateChanged, this);
523 ecore_imf_context_input_panel_event_callback_add(context, ECORE_IMF_CANDIDATE_PANEL_GEOMETRY_EVENT, onIMFCandidatePanelGeometryChanged, this);
524 ecore_imf_context_retrieve_surrounding_callback_set(context, onIMFRetrieveSurrounding, this);
525 ecore_imf_context_event_callback_add(context, ECORE_IMF_CALLBACK_DELETE_SURROUNDING, onIMFDeleteSurrounding, this);
526 ecore_imf_context_event_callback_add(context, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, onIMFPreeditSequenceChanged, this);
527 ecore_imf_context_event_callback_add(context, ECORE_IMF_CALLBACK_COMMIT, onIMFInputSequenceComplete, this);
529 ecore_imf_context_input_panel_layout_set(context, layout);
530 if (layoutVariation >= 0)
531 ecore_imf_context_input_panel_layout_variation_set(context, layoutVariation);
532 ecore_imf_context_input_panel_return_key_type_set(context, returnKeyType);
535 PassOwnPtr<Ecore_IMF_Context> InputMethodContextEfl::takeContext(uintptr_t contextID)
537 size_t i = m_contextList.size();
540 if (m_contextList[i].first == contextID) {
541 PassOwnPtr<Ecore_IMF_Context> context = m_contextList[i].second.release();
542 m_contextList.remove(i);
547 return PassOwnPtr<Ecore_IMF_Context>();
550 void InputMethodContextEfl::setIMFContext(const EditorState& editor)
552 const String& type = editor.inputMethodHints;
553 Ecore_IMF_Input_Panel_Layout layout;
554 int layoutVariation = -1;
555 Ecore_IMF_Input_Panel_Return_Key_Type returnKeyType = ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_DEFAULT;
557 if (type == "number") {
558 layout = ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBERONLY;
559 layoutVariation = ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBERONLY_VARIATION_NORMAL;
560 } else if (type == "signedNumber") {
561 layout = ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBERONLY;
562 layoutVariation = ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBERONLY_VARIATION_SIGNED;
563 } else if (type == "decimalNumber") {
564 layout = ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBERONLY;
565 layoutVariation = ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBERONLY_VARIATION_DECIMAL;
566 } else if (type == "signedDecimalNumber") {
567 layout = ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBERONLY;
568 layoutVariation = ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBERONLY_VARIATION_SIGNED_AND_DECIMAL;
569 } else if (type == "email")
570 layout = ECORE_IMF_INPUT_PANEL_LAYOUT_EMAIL;
571 else if (type == "url")
572 layout = ECORE_IMF_INPUT_PANEL_LAYOUT_URL;
573 else if (type == "tel")
574 layout = ECORE_IMF_INPUT_PANEL_LAYOUT_PHONENUMBER;
575 else if (type == "password")
576 layout = ECORE_IMF_INPUT_PANEL_LAYOUT_PASSWORD;
578 layout = ECORE_IMF_INPUT_PANEL_LAYOUT_NORMAL;
579 if (type == "search")
580 returnKeyType = ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_SEARCH;
583 OwnPtr<Ecore_IMF_Context> context;
584 if (m_contextID == editor.inputMethodContextID)
585 context = m_context.release();
587 context = takeContext(editor.inputMethodContextID);
592 context = createIMFContext(evas_object_evas_get(m_viewImpl->view()));
595 initializeIMFContext(context.get(), layout, layoutVariation, returnKeyType);
598 m_context = context.release();
599 m_contextID = editor.inputMethodContextID;
601 if (type == "password" || type == "plugin")
602 ecore_imf_context_prediction_allow_set(m_context.get(), false);
604 ecore_imf_context_prediction_allow_set(m_context.get(), true);
606 if (type.isEmpty() || type == "textarea")
607 ecore_imf_context_autocapital_type_set(m_context.get(), ECORE_IMF_AUTOCAPITAL_TYPE_SENTENCE);
609 ecore_imf_context_autocapital_type_set(m_context.get(), ECORE_IMF_AUTOCAPITAL_TYPE_NONE);
612 bool InputMethodContextEfl::isShow()
614 return (m_context && m_focused && ecore_imf_context_input_panel_state_get(m_context.get()) != ECORE_IMF_INPUT_PANEL_STATE_HIDE);
617 Ecore_IMF_Autocapital_Type InputMethodContextEfl::autoCapitalType()
619 return (m_context ? ecore_imf_context_autocapital_type_get(m_context.get()) : ECORE_IMF_AUTOCAPITAL_TYPE_NONE);
622 void InputMethodContextEfl::onFocusIn()
624 if (m_inputPickerType >= 0) {
625 showInputPicker(m_viewImpl->page()->editorState());
629 if (!m_context || !m_focused)
632 ecore_imf_context_focus_in(m_context.get());
633 ecore_imf_context_input_panel_show(m_context.get());
634 if (!isSystemKeypadShow())
635 setState(ECORE_IMF_INPUT_PANEL_STATE_WILL_SHOW);
638 void InputMethodContextEfl::onFocusOut()
640 #if ENABLE(TIZEN_WEBKIT2_CONTEXT_MENU_CLIPBOARD)
641 if (m_state != ECORE_IMF_INPUT_PANEL_STATE_SHOW) {
642 if (m_viewImpl->pageClient->isClipboardWindowOpened())
643 m_viewImpl->pageClient->closeClipboardWindow();
647 #if ENABLE(TIZEN_FOCUS_UI)
648 m_viewImpl->page()->setFocusUIEnabled(false);
651 if (!m_context || !m_focused)
654 ecore_imf_context_input_panel_hide(m_context.get());
655 ecore_imf_context_focus_out(m_context.get());
658 void InputMethodContextEfl::revertIMFContext()
663 if (m_contextList.size() >= maxContextSize)
664 m_contextList.remove(0);
666 PassOwnPtr<Ecore_IMF_Context> imfContext = m_context.release();
667 m_contextList.append(std::make_pair(m_contextID, imfContext));
671 void InputMethodContextEfl::resetIMFContext()
676 m_doNotHandleFakeKeyEvent = true;
677 ecore_imf_context_reset(m_context.get());
678 m_doNotHandleFakeKeyEvent = false;
681 void InputMethodContextEfl::showIMFContext(const EditorState& editor, bool isUserAction)
683 Ewk_Settings* settings = ewk_view_settings_get(m_viewImpl->view());
684 bool isContextTransition = (m_contextID && m_contextID != editor.inputMethodContextID);
686 if (!isUserAction && !isContextTransition) {
687 if (!ewk_settings_uses_keypad_without_user_action_get(settings) || (m_focused && m_contextID == editor.inputMethodContextID))
691 #if ENABLE(TIZEN_WEBKIT2_CONTEXT_MENU_CLIPBOARD)
692 if (m_viewImpl->pageClient->isClipboardWindowOpened())
696 if (m_contextID != editor.inputMethodContextID)
701 #if ENABLE(TIZEN_INPUT_TAG_EXTENSION)
702 if (editor.inputMethodHints == "date")
703 m_inputPickerType = EWK_INPUT_TYPE_DATE;
704 else if (editor.inputMethodHints == "datetime")
705 m_inputPickerType = EWK_INPUT_TYPE_DATETIME;
706 else if (editor.inputMethodHints == "datetime-local")
707 m_inputPickerType = EWK_INPUT_TYPE_DATETIMELOCAL;
708 else if (editor.inputMethodHints == "month")
709 m_inputPickerType = EWK_INPUT_TYPE_MONTH;
710 else if (editor.inputMethodHints == "time")
711 m_inputPickerType = EWK_INPUT_TYPE_TIME;
712 else if (editor.inputMethodHints == "week")
713 m_inputPickerType = EWK_INPUT_TYPE_WEEK;
715 m_inputPickerType = -1;
717 if (m_inputPickerType >= 0) {
718 showInputPicker(editor);
719 m_contextID = editor.inputMethodContextID;
723 #endif // ENABLE(TIZEN_INPUT_TAG_EXTENSION)
725 bool hasFocus = evas_object_focus_get(m_viewImpl->view());
727 if (!ewk_settings_default_keypad_enabled_get(settings)) {
729 Eina_Rectangle dummyRectForCustomKeypadCallback;
730 memset(&dummyRectForCustomKeypadCallback, 0, sizeof(Eina_Rectangle));
731 evas_object_smart_callback_call(m_viewImpl->view(), "inputmethod,changed", &dummyRectForCustomKeypadCallback);
736 setIMFContext(editor);
743 // input field zoom for external keyboard
744 if (s_shouldUseExternalKeyboard)
745 ewk_view_focused_node_adjust(m_viewImpl->view(), EINA_TRUE);
748 ewk_view_focused_node_adjust(m_viewImpl->view());
752 ecore_imf_context_focus_in(m_context.get());
753 ecore_imf_context_input_panel_show(m_context.get());
754 setState(ECORE_IMF_INPUT_PANEL_STATE_WILL_SHOW);
757 void InputMethodContextEfl::hideIMFContext()
759 #if ENABLE(TIZEN_WEBKIT2_CONTEXT_MENU_CLIPBOARD)
760 if (m_state != ECORE_IMF_INPUT_PANEL_STATE_SHOW) {
761 if (m_viewImpl->pageClient->isClipboardWindowOpened())
762 m_viewImpl->pageClient->closeClipboardWindow();
766 m_inputPickerType = -1;
768 if (!m_context || !m_focused)
771 if (evas_object_focus_get(m_viewImpl->view())) {
773 ecore_imf_context_input_panel_hide(m_context.get());
774 ecore_imf_context_focus_out(m_context.get());
781 void InputMethodContextEfl::destroyIMFContextList()
783 m_contextList.clear();
786 #if ENABLE(TIZEN_INPUT_TAG_EXTENSION)
787 void InputMethodContextEfl::showInputPicker(const EditorState& editorState)
789 if (editorState.selectionIsRange || !evas_object_focus_get(m_viewImpl->view()))
792 ewkViewInputPickerRequest(m_viewImpl->view(), static_cast<Ewk_Input_Type>(m_inputPickerType), editorState.surroundingText);
793 m_inputPickerType = -1;
797 bool InputMethodContextEfl::isIMEPostion(int x, int y)
799 if (m_state == ECORE_IMF_INPUT_PANEL_STATE_SHOW)
800 return m_imeRect.contains(x, y);
805 void InputMethodContextEfl::removeIMFContext(uintptr_t contextID)
807 if (m_contextID == contextID)
810 takeContext(contextID);
813 void InputMethodContextEfl::requestFakeKeyEvent()
815 if (m_doNotHandleFakeKeyEvent || m_fakeKeyEventTimer.isActive())
818 m_fakeKeyEventTimer.startOneShot(0);
819 m_viewImpl->page()->prepareKeyDownEvent();
822 void InputMethodContextEfl::fakeKeyEventTimerFired(WebCore::Timer<InputMethodContextEfl>*)
825 if (!m_approximateSurroundingText.isNull()) {
826 if (!m_approximateCursorPosition)
827 ch = m_approximateSurroundingText[0];
828 else if (m_approximateCursorPosition > m_approximateSurroundingText.length())
829 ch = m_approximateSurroundingText[m_approximateSurroundingText.length() - 1];
831 ch = m_approximateSurroundingText[m_approximateCursorPosition - 1];
835 if (Unicode::isSeparatorSpace(ch))
837 else if (Unicode::isPrintableChar(ch))
842 CString stringForEvent = string.utf8();
843 const char* data = stringForEvent.data();
845 Evas_Event_Key_Down downEvent;
846 memset(&downEvent, 0, sizeof(Evas_Event_Key_Down));
847 downEvent.key = data;
848 downEvent.string = data;
849 NativeWebKeyboardEvent nativeEvent(&downEvent, true);
850 nativeEvent.setInputMethodContextID(m_viewImpl->page()->editorState().inputMethodContextID);
851 m_viewImpl->page()->handleKeyboardEvent(nativeEvent);
853 Evas_Event_Key_Up upEvent;
854 memset(&upEvent, 0, sizeof(Evas_Event_Key_Up));
856 upEvent.string = data;
857 m_viewImpl->page()->handleKeyboardEvent(NativeWebKeyboardEvent(&upEvent));
860 void InputMethodContextEfl::updateApproximateText(const String& text, unsigned removePosition, unsigned removeLength)
862 if (m_approximateSurroundingText.isNull()) {
863 const EditorState& state = m_viewImpl->page()->editorState();
865 m_approximateSurroundingText = state.surroundingText;
866 if (m_approximateSurroundingText.isNull())
867 m_approximateSurroundingText = emptyString();
868 m_approximateCursorPosition = state.cursorPosition;
871 if (!text.isNull()) {
872 m_approximateSurroundingText.insert(text, m_approximateCursorPosition);
873 m_approximateCursorPosition += text.length();
875 m_approximateSurroundingText.remove(removePosition, removeLength);
876 if (m_approximateCursorPosition > removePosition && m_approximateCursorPosition <= removePosition + removeLength)
877 m_approximateCursorPosition = removePosition;
881 bool InputMethodContextEfl::recalcFilterEvent(const Ecore_IMF_Event* event)
886 m_doNotHandleFakeKeyEvent = true;
887 bool isFiltered = ecore_imf_context_filter_event(m_context.get(), ECORE_IMF_EVENT_KEY_DOWN, const_cast<Ecore_IMF_Event*>(event));
888 m_doNotHandleFakeKeyEvent = false;
892 #endif // #if ENABLE(TIZEN_ISF_PORT)