Bug 1300003 part.5 Remove odd WM_CHAR messages which are caused by ATOK or WXG (both of them are Japanese IME) r?m_kato draft
authorMasayuki Nakano <masayuki@d-toybox.com>
Wed, 14 Sep 2016 16:20:53 +0900
changeset 413991 a77662f5a55b71dba06f333e85a72cce120637c4
parent 413990 40915aece9abb9480d96d00c455c3dad50b8c801
child 413992 71f477b9e3b20af4a57170667b75a686453a039e
push id29569
push usermasayuki@d-toybox.com
push dateThu, 15 Sep 2016 12:25:58 +0000
reviewersm_kato
bugs1300003
milestone51.0a1
Bug 1300003 part.5 Remove odd WM_CHAR messages which are caused by ATOK or WXG (both of them are Japanese IME) r?m_kato NativeKey removes odd WM_CHAR messages which are caused by ATOK or WXG if the user tries to do "Kakutei-Undo" (meaning "undo the last commit") after dispatching eKeyDown event. However, NativeKey should remove them from the queue first because there are some problems: * If focus is moved during dispatching an eKeyDown event, we'll fail to remove the messages from the queue. * If dispatching eKeyDown advance native event loop due to entering to a modal loop or dosing synchronous XHR, the message pattern is broken before removing the odd messages from the queue. After removing the odd char messages, NativeKey should store them with mRemovedOddCharMsgs because NativeKey needs to dispatch them to focused windowless plugin. Note that this patch also fixes a bug of the loop to remove the odd WM_CHAR messages. Old code removes only one WM_CHAR messages, but we need to remove all WM_CHAR messages before WM_KEYUP. This must be a regression. MozReview-Commit-ID: I60bcIx2SFS
widget/windows/KeyboardLayout.cpp
widget/windows/KeyboardLayout.h
--- a/widget/windows/KeyboardLayout.cpp
+++ b/widget/windows/KeyboardLayout.cpp
@@ -1104,16 +1104,18 @@ NativeKey::NativeKey(nsWindowBase* aWidg
         char16_t ch = static_cast<char16_t>(mFollowingCharMsgs[i].wParam);
         // Skip control characters.
         if (IsControlChar(ch)) {
           continue;
         }
         mCommittedCharsAndModifiers.Append(ch, mModKeyState.GetModifiers());
       }
     }
+    // Remove odd char messages if there are.
+    RemoveFollowingOddCharMessages();
   }
 }
 
 NativeKey::~NativeKey()
 {
   if (mIsOverridingKeyboardLayout) {
     KeyboardLayout* keyboardLayout = KeyboardLayout::GetInstance();
     keyboardLayout->RestoreLayout();
@@ -1273,16 +1275,57 @@ NativeKey::IsIMEDoingKakuteiUndo() const
          startCompositionMsg.lParam == 0x0 &&
          compositionMsg.wParam == 0x0 &&
          compositionMsg.lParam == 0x1BF &&
          charMsg.wParam == VK_BACK && charMsg.lParam == 0x1 &&
          startCompositionMsg.time <= compositionMsg.time &&
          compositionMsg.time <= charMsg.time;
 }
 
+void
+NativeKey::RemoveFollowingOddCharMessages()
+{
+  MOZ_ASSERT(IsKeyDownMessage());
+
+  // If the keydown message is synthesized for automated tests, there is
+  // nothing to do here.
+  if (mFakeCharMsgs) {
+    return;
+  }
+
+  // If there are some following char messages before another key message,
+  // there is nothing to do here.
+  if (!mFollowingCharMsgs.IsEmpty()) {
+    return;
+  }
+
+  // If the handling key isn't Backspace, there is nothing to do here.
+  if (mOriginalVirtualKeyCode != VK_BACK) {
+    return;
+  }
+
+  // If we don't see the odd message pattern, there is nothing to do here.
+  if (!IsIMEDoingKakuteiUndo()) {
+    return;
+  }
+
+  // Otherwise, we need to remove odd WM_CHAR messages for ATOK or WXG (both
+  // of them are Japanese IME).
+  MSG msg;
+  while (WinUtils::PeekMessage(&msg, mMsg.hwnd, WM_CHAR, WM_CHAR,
+                               PM_REMOVE | PM_NOYIELD)) {
+    if (msg.message != WM_CHAR) {
+      MOZ_RELEASE_ASSERT(msg.message == WM_NULL,
+                         "Unexpected message was removed");
+      continue;
+    }
+    mRemovedOddCharMsgs.AppendElement(msg);
+  }
+}
+
 UINT
 NativeKey::GetScanCodeWithExtendedFlag() const
 {
   // MapVirtualKeyEx() has been improved for supporting extended keys since
   // Vista.  When we call it for mapping a scancode of an extended key and
   // a virtual keycode, we need to add 0xE000 to the scancode.
   // On Win XP and Win Server 2003, this doesn't support. On them, we have
   // no way to get virtual keycodes from scancode of extended keys.
@@ -2341,44 +2384,34 @@ NativeKey::GetFollowingCharMessage(MSG& 
 
 // TODO: Rename this method later.
 bool
 NativeKey::DispatchPluginEventsAndDiscardsCharMessages() const
 {
   MOZ_ASSERT(IsKeyDownMessage());
   MOZ_ASSERT(!IsKeyMessageOnPlugin());
 
-  bool anyCharMessagesRemoved = false;
   for (size_t i = 0; i < mFollowingCharMsgs.Length(); ++i) {
-    anyCharMessagesRemoved = true;
     MOZ_RELEASE_ASSERT(!mWidget->Destroyed(),
       "NativeKey tries to dispatch a plugin event on destroyed widget");
     mWidget->DispatchPluginEvent(mFollowingCharMsgs[i]);
     if (mWidget->Destroyed() || IsFocusedWindowChanged()) {
       return true;
     }
   }
 
-  if (!mFakeCharMsgs && !anyCharMessagesRemoved &&
-      mDOMKeyCode == NS_VK_BACK && IsIMEDoingKakuteiUndo()) {
-    // This is for a hack for ATOK and WXG.  So, PeekMessage() must scceed!
-    MSG msg;
-    while (WinUtils::PeekMessage(&msg, mMsg.hwnd, WM_CHAR, WM_CHAR,
-                                 PM_REMOVE | PM_NOYIELD)) {
-      if (msg.message != WM_CHAR) {
-        MOZ_RELEASE_ASSERT(msg.message == WM_NULL,
-                           "Unexpected message was removed");
-        continue;
-      }
-      MOZ_RELEASE_ASSERT(!mWidget->Destroyed(),
-        "NativeKey tries to dispatch a plugin event on destroyed widget");
-      mWidget->DispatchPluginEvent(msg);
-      return mWidget->Destroyed();
+  // Dispatch odd char messages which are caused by ATOK or WXG (both of them
+  // are Japanese IME) and removed by RemoveFollowingOddCharMessages().
+  for (size_t i = 0; i < mRemovedOddCharMsgs.Length(); ++i) {
+    MOZ_RELEASE_ASSERT(!mWidget->Destroyed(),
+      "NativeKey tries to dispatch a plugin event on destroyed widget");
+    mWidget->DispatchPluginEvent(mRemovedOddCharMsgs[i]);
+    if (mWidget->Destroyed() || IsFocusedWindowChanged()) {
+      return true;
     }
-    MOZ_CRASH("NativeKey failed to get WM_CHAR for ATOK or WXG");
   }
 
   return false;
 }
 
 void
 NativeKey::ComputeInputtingStringWithKeyboardLayout()
 {
--- a/widget/windows/KeyboardLayout.h
+++ b/widget/windows/KeyboardLayout.h
@@ -262,16 +262,20 @@ private:
   RefPtr<nsWindowBase> mWidget;
   RefPtr<TextEventDispatcher> mDispatcher;
   HKL mKeyboardLayout;
   MSG mMsg;
   // mFollowingCharMsgs stores WM_CHAR, WM_SYSCHAR, WM_DEADCHAR or
   // WM_SYSDEADCHAR message which follows WM_KEYDOWN.
   // Note that the stored messaged are already removed from the queue.
   nsTArray<MSG> mFollowingCharMsgs;
+  // mRemovedOddCharMsgs stores WM_CHAR messages which are caused by ATOK or
+  // WXG (they are Japanese IME) when the user tries to do "Kakutei-undo"
+  // (it means "undo the last commit").
+  nsTArray<MSG> mRemovedOddCharMsgs;
   // If dispatching eKeyDown or eKeyPress event causes focus change,
   // the instance shouldn't handle remaning char messages.  For checking it,
   // this should store first focused window.
   HWND mFocusedWndBeforeDispatch;
 
   uint32_t mDOMKeyCode;
   KeyNameIndex mKeyNameIndex;
   CodeNameIndex mCodeNameIndex;
@@ -372,16 +376,22 @@ private:
   }
 
   UINT GetScanCodeWithExtendedFlag() const;
 
   // The result is one of nsIDOMKeyEvent::DOM_KEY_LOCATION_*.
   uint32_t GetKeyLocation() const;
 
   /**
+   * RemoveFollowingOddCharMessages() removes odd WM_CHAR messages from the
+   * queue when IsIMEDoingKakuteiUndo() returns true.
+   */
+  void RemoveFollowingOddCharMessages();
+
+  /**
    * "Kakutei-Undo" of ATOK or WXG (both of them are Japanese IME) causes
    * strange WM_KEYDOWN/WM_KEYUP/WM_CHAR message pattern.  So, when this
    * returns true, the caller needs to be careful for processing the messages.
    */
   bool IsIMEDoingKakuteiUndo() const;
 
   bool IsKeyDownMessage() const
   {