Bug 1305943 Don't consume following WM_SYSCHAR message for some key combinations which are reserved by the system r?m_kato draft
authorMasayuki Nakano <masayuki@d-toybox.com>
Fri, 30 Sep 2016 17:32:34 +0900
changeset 419952 d80a45017b15a2c766d1515b18caa42ca6f8f82e
parent 419951 ec5a01d9d8ed80b9d9685be55d6b816eadb39c5b
child 532683 592c3b606af621e23e57cc8c3faf5321a13ae250
push id31050
push usermasayuki@d-toybox.com
push dateMon, 03 Oct 2016 00:54:38 +0000
reviewersm_kato
bugs1305943, 1300003
milestone52.0a1
Bug 1305943 Don't consume following WM_SYSCHAR message for some key combinations which are reserved by the system r?m_kato When key combination is reserved by the system, web apps shouldn't be able to consume the key events. In such case, we've decided that we never expose the key events in web contents (including chrome contents). Therefore, NativeKey stops dispatching keyboard events only for Alt+Space. However, new code of the fix of bug 1300003 always consumes WM_SYSCHAR which follows WM_SYSKEYDOWN of Alt+Space. This is the cause of bug 1305943. For fixing this bug, NativeKey should have a helper method, IsReservedBySystem(), and when it returns true, it should do nothing when Handle*Message() is called and should not consume following WM_SYSCHAR messages at handling WM_*KEYDOWN. Unfortunately, it's impossible to test this regression because nsDOMWindowUtils::SendNativeKeyEvent() may call nsIWidget::SynthesizeNativeKeyEvent() asynchronously. See <https://dxr.mozilla.org/mozilla-central/source/dom/base/nsDOMWindowUtils.cpp#1105-1108>. Therefore, it cannot return if it's consumed. MozReview-Commit-ID: 9ABh2rYNkFs
widget/windows/KeyboardLayout.cpp
widget/windows/KeyboardLayout.h
--- a/widget/windows/KeyboardLayout.cpp
+++ b/widget/windows/KeyboardLayout.cpp
@@ -1272,33 +1272,17 @@ NativeKey::NativeKey(nsWindowBase* aWidg
 
 void
 NativeKey::InitWithKeyChar()
 {
   mScanCode = WinUtils::GetScanCode(mMsg.lParam);
   mIsExtended = WinUtils::IsExtendedScanCode(mMsg.lParam);
   switch (mMsg.message) {
     case WM_KEYDOWN:
-    case WM_SYSKEYDOWN: {
-      // If next message is WM_*CHAR message, let's consume it now.
-      MSG charMsg;
-      while (GetFollowingCharMessage(charMsg)) {
-        // Although, got message shouldn't be WM_NULL in desktop apps,
-        // we should keep checking this.  FYI: This was added for Metrofox.
-        if (charMsg.message == WM_NULL) {
-          continue;
-        }
-        MOZ_LOG(sNativeKeyLogger, LogLevel::Info,
-          ("%p   NativeKey::InitWithKeyChar(), removed char message, %s",
-           this, ToString(charMsg).get()));
-        NS_WARN_IF(charMsg.hwnd != mMsg.hwnd);
-        mFollowingCharMsgs.AppendElement(charMsg);
-      }
-      MOZ_FALLTHROUGH;
-    }
+    case WM_SYSKEYDOWN:
     case WM_KEYUP:
     case WM_SYSKEYUP:
     case MOZ_WM_KEYDOWN:
     case MOZ_WM_KEYUP: {
       // First, resolve the IME converted virtual keycode to its original
       // keycode.
       if (mMsg.wParam == VK_PROCESSKEY) {
         mOriginalVirtualKeyCode =
@@ -1478,16 +1462,36 @@ NativeKey::InitWithKeyChar()
   //      handling a keydown message.
   mKeyNameIndex = IsFollowedByNonControlCharMessage() ?
     KEY_NAME_INDEX_USE_STRING :
     keyboardLayout->ConvertNativeKeyCodeToKeyNameIndex(mOriginalVirtualKeyCode);
   mCodeNameIndex =
     KeyboardLayout::ConvertScanCodeToCodeNameIndex(
       GetScanCodeWithExtendedFlag());
 
+  // If next message of WM_(SYS)KEYDOWN is WM_*CHAR message and the key
+  // combination is not reserved by the system, let's consume it now.
+  if ((mMsg.message == WM_KEYDOWN || mMsg.message == WM_SYSKEYDOWN) &&
+      !IsReservedBySystem()) {
+    MSG charMsg;
+    while (GetFollowingCharMessage(charMsg)) {
+      // Although, got message shouldn't be WM_NULL in desktop apps,
+      // we should keep checking this.  FYI: This was added for Metrofox.
+      if (charMsg.message == WM_NULL) {
+        continue;
+      }
+      MOZ_LOG(sNativeKeyLogger, LogLevel::Info,
+        ("%p   NativeKey::InitWithKeyChar(), removed char message, %s",
+         this, ToString(charMsg).get()));
+      NS_WARN_IF(charMsg.hwnd != mMsg.hwnd);
+      mFollowingCharMsgs.AppendElement(charMsg);
+    }
+  }
+
+
   keyboardLayout->InitNativeKey(*this, mModKeyState);
 
   mIsDeadKey =
     (IsFollowedByDeadCharMessage() ||
      keyboardLayout->IsDeadKey(mOriginalVirtualKeyCode, mModKeyState));
   mIsPrintableKey =
     mKeyNameIndex == KEY_NAME_INDEX_USE_STRING ||
     KeyboardLayout::IsPrintableCharKey(mOriginalVirtualKeyCode);
@@ -1659,16 +1663,32 @@ NativeKey::IsFollowedByNonControlCharMes
   if (mFollowingCharMsgs.IsEmpty()) {
     return false;
   }
   return mFollowingCharMsgs[0].message == WM_CHAR &&
          !IsControlChar(static_cast<char16_t>(mFollowingCharMsgs[0].wParam));
 }
 
 bool
+NativeKey::IsReservedBySystem() const
+{
+  // Alt+Space key is handled by OS, we shouldn't touch it.
+  if (mModKeyState.IsAlt() && !mModKeyState.IsControl() &&
+      mVirtualKeyCode == VK_SPACE) {
+    return true;
+  }
+
+  // XXX How about Alt+F4? We receive WM_SYSKEYDOWN for F4 before closing the
+  //     window.  Although, we don't prevent to close the window but the key
+  //     event shouldn't be exposed to the web.
+
+  return false;
+}
+
+bool
 NativeKey::IsIMEDoingKakuteiUndo() const
 {
   // Following message pattern is caused by "Kakutei-Undo" of ATOK or WXG:
   // ---------------------------------------------------------------------------
   // WM_KEYDOWN              * n (wParam = VK_BACK, lParam = 0x1)
   // WM_KEYUP                * 1 (wParam = VK_BACK, lParam = 0xC0000001) # ATOK
   // WM_IME_STARTCOMPOSITION * 1 (wParam = 0x0, lParam = 0x0)
   // WM_IME_COMPOSITION      * 1 (wParam = 0x0, lParam = 0x1BF)
@@ -2243,28 +2263,26 @@ NativeKey::HandleKeyDownMessage(bool* aE
     sDispatchedKeyOfAppCommand = 0;
     MOZ_LOG(sNativeKeyLogger, LogLevel::Info,
       ("%p   NativeKey::HandleKeyDownMessage(), doesn't dispatch keydown "
        "event due to already dispatched from HandleAppCommandMessage(), ",
        this));
     return true;
   }
 
+  if (IsReservedBySystem()) {
+    MOZ_LOG(sNativeKeyLogger, LogLevel::Info,
+      ("%p   NativeKey::HandleKeyDownMessage(), doesn't dispatch keydown "
+       "event because the key combination is reserved by the system", this));
+    return false;
+  }
+
   bool defaultPrevented = false;
   if (mFakeCharMsgs || IsKeyMessageOnPlugin() ||
       !RedirectedKeyDownMessageManager::IsRedirectedMessage(mMsg)) {
-    // Ignore [shift+]alt+space so the OS can handle it.
-    if (mModKeyState.IsAlt() && !mModKeyState.IsControl() &&
-        mVirtualKeyCode == VK_SPACE) {
-      MOZ_LOG(sNativeKeyLogger, LogLevel::Info,
-        ("%p   NativeKey::HandleKeyDownMessage(), doesn't dispatch keydown "
-         "event due to Alt+Space", this));
-      return false;
-    }
-
     nsresult rv = mDispatcher->BeginNativeInputTransaction();
     if (NS_WARN_IF(NS_FAILED(rv))) {
       MOZ_LOG(sNativeKeyLogger, LogLevel::Error,
         ("%p   NativeKey::HandleKeyDownMessage(), FAILED due to "
          "BeginNativeInputTransaction() failure", this));
       return true;
     }
 
@@ -2484,22 +2502,22 @@ NativeKey::HandleCharMessage(const MSG& 
     MOZ_LOG(sNativeKeyLogger, LogLevel::Warning,
       ("%p   NativeKey::HandleCharMessage(), WARNING, does nothing because "
        "the message should be handled in another instance removing this "
        "message", this));
     // Consume this for now because it will be handled by another instance.
     return true;
   }
 
-  // Alt+Space key is handled by OS, we shouldn't touch it.
-  if (mModKeyState.IsAlt() && !mModKeyState.IsControl() &&
-      mVirtualKeyCode == VK_SPACE) {
+  // If the key combinations is reserved by the system, we shouldn't dispatch
+  // eKeyPress event for it and passes the message to next wndproc.
+  if (IsReservedBySystem()) {
     MOZ_LOG(sNativeKeyLogger, LogLevel::Info,
       ("%p   NativeKey::HandleCharMessage(), doesn't dispatch keypress "
-       "event due to Alt+Space", this));
+       "event because the key combination is reserved by the system", this));
     return false;
   }
 
   // Bug 818235: Ignore Ctrl+Enter.
   if (!mModKeyState.IsAlt() && mModKeyState.IsControl() &&
       mVirtualKeyCode == VK_RETURN) {
     MOZ_LOG(sNativeKeyLogger, LogLevel::Info,
       ("%p   NativeKey::HandleCharMessage(), doesn't dispatch keypress "
@@ -2687,22 +2705,22 @@ bool
 NativeKey::HandleKeyUpMessage(bool* aEventDispatched) const
 {
   MOZ_ASSERT(IsKeyUpMessage());
 
   if (aEventDispatched) {
     *aEventDispatched = false;
   }
 
-  // Ignore [shift+]alt+space so the OS can handle it.
-  if (mModKeyState.IsAlt() && !mModKeyState.IsControl() &&
-      mVirtualKeyCode == VK_SPACE) {
+  // If the key combinations is reserved by the system, we shouldn't dispatch
+  // eKeyUp event for it and passes the message to next wndproc.
+  if (IsReservedBySystem()) {
     MOZ_LOG(sNativeKeyLogger, LogLevel::Info,
       ("%p   NativeKey::HandleKeyUpMessage(), doesn't dispatch keyup "
-       "event due to Alt+Space", this));
+       "event because the key combination is reserved by the system", this));
     return false;
   }
 
   nsresult rv = mDispatcher->BeginNativeInputTransaction();
   if (NS_WARN_IF(NS_FAILED(rv))) {
     MOZ_LOG(sNativeKeyLogger, LogLevel::Error,
       ("%p   NativeKey::HandleKeyUpMessage(), FAILED due to "
        "BeginNativeInputTransaction() failure", this));
@@ -2745,16 +2763,22 @@ NativeKey::NeedsToHandleWithoutFollowing
 
   // We cannot know following char messages of key messages in a plugin
   // process.  So, let's compute the character to be inputted with every
   // printable key should be computed with the keyboard layout.
   if (IsKeyMessageOnPlugin()) {
     return true;
   }
 
+  // If the key combination is reserved by the system, the caller shouldn't
+  // do anything with following WM_*CHAR messages.  So, let's return true here.
+  if (IsReservedBySystem()) {
+    return true;
+  }
+
   // If the keydown message is generated for inputting some Unicode characters
   // via SendInput() API, we need to handle it only with WM_*CHAR messages.
   if (mVirtualKeyCode == VK_PACKET) {
     return false;
   }
 
   // Enter and backspace are always handled here to avoid for example the
   // confusion between ctrl-enter and ctrl-J.
--- a/widget/windows/KeyboardLayout.h
+++ b/widget/windows/KeyboardLayout.h
@@ -470,16 +470,23 @@ private:
   bool IsFollowedByDeadCharMessage() const;
   bool IsKeyMessageOnPlugin() const
   {
     return (mMsg.message == MOZ_WM_KEYDOWN ||
             mMsg.message == MOZ_WM_KEYUP);
   }
 
   /**
+   * IsReservedBySystem() returns true if the key combination is reserved by
+   * the system.  Even if it's consumed by web apps, the message should be
+   * sent to next wndproc.
+   */
+  bool IsReservedBySystem() const;
+
+  /**
    * GetFollowingCharMessage() returns following char message of handling
    * keydown event.  If the message is found, this method returns true.
    * Otherwise, returns false.
    *
    * WARNING: Even if this returns true, aCharMsg may be WM_NULL or its
    *          hwnd may be different window.
    */
   bool GetFollowingCharMessage(MSG& aCharMsg);