Fix IME events handling.
authorKarol Furmaniak <k.furmaniak@samsung.com>
Fri, 13 Jun 2014 23:24:47 +0000 (16:24 -0700)
committerYoungsoo Choi <kenshin.choi@samsung.com>
Tue, 10 Jul 2018 06:57:09 +0000 (06:57 +0000)
Issue: CBBROWSER-94, CBBROWSER-95, CBBROWSER-93, CBBROWSER-96, CBBROWSER-228, CBBROWSER-229, CBBROWSER-227,

[Problem]: Tests form issuses above are failing.
[Cause]: Some of IME events are not dispatched and others are in unproper order.
[Solution]: Change handling IME events as it is in Webkit.

Change-Id: I876a3c6da9f19dfb6dea08e2d53b59ccd3bd3c8b

Conflicts:

impl/browser/renderer_host/im_context_efl.cc
impl/browser/renderer_host/render_widget_host_view_efl.cc
impl/browser/renderer_host/render_widget_host_view_efl.h
src/content/renderer/render_widget.cc

tizen_src/impl/browser/renderer_host/im_context_efl.cc
tizen_src/impl/browser/renderer_host/im_context_efl.h
tizen_src/impl/browser/renderer_host/render_widget_host_view_efl.cc
tizen_src/impl/browser/renderer_host/render_widget_host_view_efl.h

index 598cded..afd3b3f 100644 (file)
@@ -27,6 +27,8 @@
 
 #include <Ecore_Evas.h>
 #include <Ecore_IMF_Evas.h>
+#include "wtf/unicode/icu/UnicodeIcu.h"
+#include "third_party/icu/source/common/unicode/uchar.h"
 
 #ifdef IM_CTX_DEBUG
 #define IM_CTX_LOG_CHANNEL LOG(ERROR)
@@ -81,7 +83,8 @@ IMContextEfl::IMContextEfl(RenderWidgetHostViewEfl* view, Ecore_IMF_Context* con
       focused_(false),
       enabled_(false),
       panel_was_ever_shown_(false),
-      is_in_form_tag_(false) {
+      is_in_form_tag_(false),
+      is_handling_keydown_(false) {
   IM_CTX_LOG;
   InitializeIMFContext(context_);
 }
@@ -115,13 +118,17 @@ IMContextEfl::~IMContextEfl() {
 
 void IMContextEfl::Reset() {
   ecore_imf_context_reset(context_);
+  ClearQueues();
+  view_->ClearQueues();
 }
 
 void IMContextEfl::HandleKeyDownEvent(const Evas_Event_Key_Down* event, bool* wasFiltered) {
 #if USE_IM_COMPOSITING
   Ecore_IMF_Event im_event;
+  is_handling_keydown_ = true;
   ecore_imf_evas_event_key_down_wrap(const_cast<Evas_Event_Key_Down*>(event), &im_event.key_down);
   *wasFiltered = ecore_imf_context_filter_event(context_, ECORE_IMF_EVENT_KEY_DOWN, &im_event);
+  is_handling_keydown_ = false;
 #endif
 }
 
@@ -144,6 +151,9 @@ void IMContextEfl::UpdateInputMethodState(ui::TextInputType input_type,
   enabled_ = enabled;
   ecore_imf_context_reset(context_);
 
+  ClearQueues();
+  view_->ClearQueues();
+
   // This can only be called when having focus since we disable IME messages in OnFocusOut.
   DCHECK(focused_);
 
@@ -278,6 +288,10 @@ void IMContextEfl::UpdateCaretBounds(const gfx::Rect& caret_bounds) {
 }
 
 void IMContextEfl::OnFocusIn() {
+
+  ClearQueues();
+  view_->ClearQueues();
+
   if (focused_)
     return;
 
@@ -312,6 +326,9 @@ void IMContextEfl::OnFocusOut() {
   // Disable RenderWidget's IME related events to save bandwidth.
   if (view_->GetRenderWidgetHost())
     RenderWidgetHostImpl::From(view_->GetRenderWidgetHost())->SetInputMethodActive(false);
+
+  ClearQueues();
+  view_->ClearQueues();
 }
 
 void IMContextEfl::CancelComposition() {
@@ -349,17 +366,57 @@ void IMContextEfl::OnCommit(void* event_info) {
 #if USE_IM_COMPOSITING
   IM_CTX_LOG;
   composition_.Clear();
-  if (view_->GetRenderWidgetHost()) {
-    char* text = static_cast<char*>(event_info);
-    base::string16 text16;
-    base::UTF8ToUTF16(text, strlen(text), &text16);
 
-    // XXX Consider doing the SendFakeCompositionKeyEvent workaround what Gtk does.
-    RenderWidgetHostImpl::From(view_->GetRenderWidgetHost())->ImeConfirmComposition(text16, gfx::Range::InvalidRange(), false);
-  }
+  char* text = static_cast<char*>(event_info);
+  base::string16 text16;
+  base::UTF8ToUTF16(text, strlen(text), &text16);
+
+  // Only add commit to queue, till we dont know if key event
+  // should be handled. It can be default prevented for exactly.
+  commit_queue_.push(text16);
+
+  // sending fake key event if hardware key is not handled as it is
+  // in Webkit.
+  SendFakeCompositionKeyEvent(text);
 #endif
 }
 
+void IMContextEfl::SendFakeCompositionKeyEvent(char * buf) {
+  if (is_handling_keydown_)
+    return;
+
+  if (!buf)
+    return;
+
+  UChar32 ch = 0;
+  if (strlen(buf)) {
+    ch = buf[strlen(buf) - 1];
+  }
+
+  std::string str;
+
+  if (u_isspace(ch))
+    str = "space";
+  else
+    str.append(1, ch);
+
+  Evas_Event_Key_Down downEvent;
+  memset(&downEvent, 0, sizeof(Evas_Event_Key_Down));
+  downEvent.key = str.c_str();
+  downEvent.string = str.c_str();
+
+  NativeWebKeyboardEvent n_event = WebEventFactoryEfl::toWebKeyboardEvent(view_->evas(), &downEvent);
+  n_event.type = blink::WebInputEvent::KeyDown;
+
+  n_event.isSystemKey = true;
+
+  if (!view_->GetRenderWidgetHost())
+    return;
+
+  view_->KeyUpEventQueuePush(n_event.windowsKeyCode);
+  view_->GetRenderWidgetHost()->ForwardKeyboardEvent(n_event);
+}
+
 void IMContextEfl::OnPreeditChanged(void* data, Ecore_IMF_Context* context, void* event_info) {
 #if USE_IM_COMPOSITING
   composition_.Clear();
@@ -370,23 +427,19 @@ void IMContextEfl::OnPreeditChanged(void* data, Ecore_IMF_Context* context, void
   if (!buffer)
       return;
 
+  SendFakeCompositionKeyEvent(buffer);
   composition_.Clear();
   composition_.text = base::UTF8ToUTF16(buffer);
-  free(buffer);
-
-  if (!view_->GetRenderWidgetHost())
-    return;
 
   composition_.underlines.push_back(ui::CompositionUnderline(0, composition_.text.length(), SK_ColorBLACK, false));
   composition_.selection = gfx::Range(composition_.text.length());
 
-  const std::vector<blink::WebCompositionUnderline>& underlines =
-      reinterpret_cast<const std::vector<blink::WebCompositionUnderline>&>(
-          composition_.underlines);
-  RenderWidgetHostImpl::From(
-      view_->GetRenderWidgetHost())->ImeSetComposition(
-          composition_.text, underlines, composition_.selection.start(),
-          composition_.selection.end());
+  // Only add preedit to queue, till we dont know if key event
+  // should be handled. It can be default prevented for exactly.
+  preedit_queue_.push(composition_);
+
+  free(buffer);
+
 #endif
 }
 
@@ -437,4 +490,14 @@ bool IMContextEfl::IsShow() {
   return (context_ && focused_ && ecore_imf_context_input_panel_state_get(context_) != ECORE_IMF_INPUT_PANEL_STATE_HIDE);
 }
 
+void IMContextEfl::ClearQueues() {
+  while (!commit_queue_.empty()) {
+    commit_queue_.pop();
+  }
+
+  while (!preedit_queue_.empty()) {
+    preedit_queue_.pop();
+  }
+}
+
 } // namespace content
index adafe81..561d45f 100644 (file)
@@ -24,6 +24,8 @@
 #include "ui/base/ime/text_input_type.h"
 #include "ui/base/ime/composition_text.h"
 #include "ui/gfx/rect.h"
+#include "content/public/browser/native_web_keyboard_event.h"
+#include "browser/renderer_host/web_event_factory_efl.h"
 
 #include <Evas.h>
 
@@ -31,6 +33,9 @@ namespace gfx {
 class Rect;
 }
 
+typedef std::queue<base::string16> CommitQueue;
+typedef std::queue<ui::CompositionText> PreeditQueue;
+
 typedef struct _Ecore_IMF_Context Ecore_IMF_Context;
 
 namespace content {
@@ -61,6 +66,13 @@ class IMContextEfl {
   void SetIsInFormTag(bool is_in_form_tag);
   bool IsShow();
   gfx::Rect GetIMERect() const { return ime_rect_; }
+  CommitQueue GetCommitQueue() { return commit_queue_; }
+  PreeditQueue GetPreeditQueue() { return preedit_queue_; }
+  void CommitQueuePop() { commit_queue_.pop(); }
+  void PreeditQueuePop() { preedit_queue_.pop(); }
+  void ClearQueues();
+
+  void SendFakeCompositionKeyEvent(char * buf);
 
  private:
   IMContextEfl(RenderWidgetHostViewEfl*, Ecore_IMF_Context*);
@@ -122,6 +134,11 @@ class IMContextEfl {
   ui::CompositionText composition_;
 
   gfx::Rect ime_rect_;
+
+  CommitQueue commit_queue_;
+  PreeditQueue preedit_queue_;
+
+  bool is_handling_keydown_;
 };
 
 } // namespace content
index c353813..b17a82d 100644 (file)
@@ -44,6 +44,7 @@
 #include "ui/views/widget/desktop_aura/desktop_screen.h"
 #include "ui/events/event_utils.h"
 #include "browser/motion/wkext_motion.h"
+#include "content/common/input_messages.h"
 
 #include <assert.h>
 #include <Ecore.h>
@@ -304,6 +305,9 @@ bool RenderWidgetHostViewEfl::OnMessageReceived(const IPC::Message& message) {
     IPC_MESSAGE_HANDLER(EwkHostMsg_DidChangePageScaleFactor, OnDidChangePageScaleFactor)
     IPC_MESSAGE_HANDLER(EwkHostMsg_DidChangePageScaleRange, OnDidChangePageScaleRange)
     IPC_MESSAGE_HANDLER(ViewHostMsg_TextInputInFormStateChanged, OnTextInputInFormStateChanged)
+#if defined(OS_TIZEN)
+    IPC_MESSAGE_HANDLER(InputHostMsg_DidInputEventHandled, OnDidInputEventHandled)
+#endif
     IPC_MESSAGE_UNHANDLED(handled = false)
   IPC_END_MESSAGE_MAP()
   return handled;
@@ -1009,8 +1013,6 @@ void RenderWidgetHostViewEfl::HandleEvasEvent(const Evas_Event_Mouse_Wheel* even
 void RenderWidgetHostViewEfl::HandleEvasEvent(const Evas_Event_Key_Down* event) {
   LOG(INFO) << __PRETTY_FUNCTION__ << " : " << event->key;
   bool wasFiltered = false;
-  if (im_context_)
-    im_context_->HandleKeyDownEvent(event, &wasFiltered);
 
   if (!strcmp(event->key, "BackSpace")) {
     SelectionControllerEfl* controller = web_view_->GetSelectionController();
@@ -1018,7 +1020,35 @@ void RenderWidgetHostViewEfl::HandleEvasEvent(const Evas_Event_Key_Down* event)
       controller->HideHandleAndContextMenu();
   }
 
-  if(!wasFiltered)
+  if (im_context_) {
+    im_context_->HandleKeyDownEvent(event, &wasFiltered);
+    NativeWebKeyboardEvent n_event = WebEventFactoryEfl::toWebKeyboardEvent(evas_, event);
+
+    if (wasFiltered)
+      n_event.isSystemKey = true;
+
+    // Do not forward keyevent now if there is fake key event
+    // handling at the moment to preserve orders of events as in Webkit
+    if (im_context_->GetPreeditQueue().empty() ||
+        keyupev_queue_.empty()) {
+      host_->ForwardKeyboardEvent(n_event);
+    } else {
+      NativeWebKeyboardEvent *n_event_ptr = new NativeWebKeyboardEvent();
+
+      n_event_ptr->timeStampSeconds = n_event.timeStampSeconds;
+      n_event_ptr->modifiers = n_event.modifiers;
+      n_event_ptr->type = n_event.type;
+      n_event_ptr->nativeKeyCode = n_event.nativeKeyCode;
+      n_event_ptr->windowsKeyCode = n_event.windowsKeyCode;
+      n_event_ptr->isSystemKey = n_event.isSystemKey;
+      n_event_ptr->unmodifiedText[0] = n_event.unmodifiedText[0];
+      n_event_ptr->text[0] = n_event.text[0];
+
+      keydownev_queue_.push(n_event_ptr);
+    }
+
+    keyupev_queue_.push(n_event.windowsKeyCode);
+  } else
     host_->ForwardKeyboardEvent(WebEventFactoryEfl::toWebKeyboardEvent(evas_, event));
 }
 
@@ -1027,8 +1057,8 @@ void RenderWidgetHostViewEfl::HandleEvasEvent(const Evas_Event_Key_Up* event) {
   if (im_context_)
     im_context_->HandleKeyUpEvent(event, &wasFiltered);
 
-  if(!wasFiltered)
-    host_->ForwardKeyboardEvent(WebEventFactoryEfl::toWebKeyboardEvent(evas_, event));
+  if (!im_context_)
+      host_->ForwardKeyboardEvent(WebEventFactoryEfl::toWebKeyboardEvent(evas_, event));
 }
 
 #ifdef OS_TIZEN
@@ -1050,6 +1080,22 @@ void RenderWidgetHostViewEfl::makePinchZoom(void* eventInfo) {
       ui::GestureEventDetails(ui::ET_GESTURE_PINCH_UPDATE, motionEvent->scale, 0), 1);
   HandleGesture(&event);
 }
+
+void RenderWidgetHostViewEfl::OnDidInputEventHandled(const blink::WebInputEvent* input_event, bool processed) {
+  if (!im_context_)
+    return;
+
+  if (blink::WebInputEvent::isKeyboardEventType(input_event->type)) {
+    if (input_event->type == blink::WebInputEvent::KeyDown) {
+
+      HandleCommitQueue(processed);
+      HandlePreeditQueue(processed);
+
+      HandleKeyUpQueue();
+      HandleKeyDownQueue();
+    }
+  }
+}
 #endif
 
 void RenderWidgetHostViewEfl::HandleGesture(ui::GestureEvent* event) {
@@ -1129,15 +1175,15 @@ void RenderWidgetHostViewEfl::HandleTouchEvent(ui::TouchEvent* event) {
   // Update the touch event first.
   blink::WebTouchPoint* point =
     content::UpdateWebTouchEventFromUIEvent(*event, &touch_event_);
-
   // Forward the touch event only if a touch point was updated, and there's a
   // touch-event handler in the page, and no other touch-event is in the queue.
   // It is important to always consume the event if there is a touch-event
   // handler in the page, or some touch-event is already in the queue, even if
   // no point has been updated, to make sure that this event does not get
   // processed by the gesture recognizer before the events in the queue.
-  if (host_->ShouldForwardTouchEvent())
+  if (host_->ShouldForwardTouchEvent()) {
     event->StopPropagation();
+  }
 
   if (point) {
     if (host_->ShouldForwardTouchEvent()) {
@@ -1212,4 +1258,87 @@ SelectionControllerEfl* RenderWidgetHostViewEfl::GetSelectionController() {
   return web_view_->GetSelectionController();
 }
 
+void RenderWidgetHostViewEfl::ClearQueues() {
+  while (!keyupev_queue_.empty()) {
+    keyupev_queue_.pop();
+  }
+
+  while (!keydownev_queue_.empty()) {
+    delete keydownev_queue_.front();
+    keydownev_queue_.pop();
+  }
+}
+
+void RenderWidgetHostViewEfl::HandleCommitQueue(bool processed) {
+  if (!im_context_)
+    return;
+
+  if (!processed) {
+    if (!im_context_->GetCommitQueue().empty()) {
+      base::string16 text16 = im_context_->GetCommitQueue().front();
+      host_->ImeConfirmComposition(text16, gfx::Range::InvalidRange(), false);
+      im_context_->CommitQueuePop();
+    }
+  } else {
+    if (!im_context_->GetCommitQueue().empty())
+      im_context_->CommitQueuePop();
+  }
+}
+
+void RenderWidgetHostViewEfl::HandlePreeditQueue(bool processed) {
+  if (!im_context_)
+    return;
+
+  if (!processed) {
+    if (!im_context_->GetPreeditQueue().empty()) {
+      ui::CompositionText composition_ = im_context_->GetPreeditQueue().front();
+
+      const std::vector<blink::WebCompositionUnderline>& underlines =
+      reinterpret_cast<const std::vector<blink::WebCompositionUnderline>&>(
+      composition_.underlines);
+
+      host_->ImeSetComposition(
+      composition_.text, underlines, composition_.selection.start(),
+      composition_.selection.end());
+      im_context_->PreeditQueuePop();
+    }
+  } else {
+    if (!im_context_->GetPreeditQueue().empty())
+      im_context_->PreeditQueuePop();
+  }
+}
+
+void RenderWidgetHostViewEfl::HandleKeyUpQueue() {
+  if (!im_context_)
+    return;
+
+  if (keyupev_queue_.empty())
+    return;
+
+  int keyCode = keyupev_queue_.front();
+  SendCompositionKeyUpEvent(keyCode);
+  keyupev_queue_.pop();
+}
+
+void RenderWidgetHostViewEfl::HandleKeyDownQueue() {
+  if (!im_context_)
+    return;
+
+  if (keydownev_queue_.empty())
+    return;
+
+  NativeWebKeyboardEvent *n_event = keydownev_queue_.front();
+  host_->ForwardKeyboardEvent(*n_event);
+  keydownev_queue_.pop();
+  delete n_event;
+}
+
+void RenderWidgetHostViewEfl::SendCompositionKeyUpEvent(char c) {
+  NativeWebKeyboardEvent event;
+  event.windowsKeyCode = c;
+  event.skip_in_browser = false;
+  event.type = blink::WebInputEvent::KeyUp;
+  host_->ForwardKeyboardEvent(event);
+}
+
 }  // namespace content
index 8e32b84..e49c8c9 100755 (executable)
 #include "ui/base/ime/text_input_client.h"
 #include "eweb_view.h"
 #include "browser/renderer_host/im_context_efl.h"
+#include "third_party/WebKit/public/web/WebInputEvent.h"
+
+#include <deque>
 #include <Evas.h>
 #include <Ecore_Evas.h>
 #include <Evas_GL.h>
+#include <Ecore_IMF_Evas.h>
 
 #ifndef OS_TIZEN
 // On desktops using mesa as GLES2 implementation GLchar is not defined
@@ -195,6 +199,7 @@ class RenderWidgetHostViewEfl
 #ifdef OS_TIZEN
   void FilterInputMotion(const blink::WebGestureEvent& gesture_event);
   void makePinchZoom(void* eventInfo);
+  void OnDidInputEventHandled(const blink::WebInputEvent* input_event, bool processed);
 #endif
 
   Evas* evas() const {
@@ -237,6 +242,8 @@ class RenderWidgetHostViewEfl
   gfx::Point ConvertPointInViewPix(gfx::Point point);
 
   void OnTextInputInFormStateChanged(bool is_in_form_tag);
+  void KeyUpEventQueuePush(int key) { keyupev_queue_.push(key); }
+  void ClearQueues();
 
  protected:
   friend class RenderWidgetHostView;
@@ -274,6 +281,12 @@ class RenderWidgetHostViewEfl
 
   Ecore_X_Window GetEcoreXWindow() const;
 
+  void HandleCommitQueue(bool processed);
+  void HandlePreeditQueue(bool processed);
+  void HandleKeyUpQueue();
+  void HandleKeyDownQueue();
+  void SendCompositionKeyUpEvent(char c);
+
   RenderWidgetHostImpl* host_;
   EWebView* web_view_;
   IMContextEfl* im_context_;
@@ -326,6 +339,12 @@ class RenderWidgetHostViewEfl
   unsigned long next_pixmap_id_;
   GLuint texture_id_;
 
+  typedef std::queue<int> KeyUpEventQueue;
+  KeyUpEventQueue keyupev_queue_;
+
+  typedef std::queue<NativeWebKeyboardEvent*> KeyDownEventQueue;
+  KeyDownEventQueue keydownev_queue_;
+
   DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostViewEfl);
 };