Bug 855975 part.16 Move keydown message redirect manager from nsWindow to widget::RedirectedKeyDownMessageManager r=jimm
authorMasayuki Nakano <masayuki@d-toybox.com>
Wed, 29 May 2013 15:34:49 +0900
changeset 133253 1f923c894ca46e2b9f500065dd6a4072d2f842c7
parent 133252 0ed82af5475f4de390a9d5c9dad982a296bd36e3
child 133254 0435d559b3147c67907392ea99c9e6d13c327e33
push id24747
push useremorley@mozilla.com
push dateWed, 29 May 2013 14:24:37 +0000
treeherdermozilla-central@8d85de779506 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjimm
bugs855975
milestone24.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 855975 part.16 Move keydown message redirect manager from nsWindow to widget::RedirectedKeyDownMessageManager r=jimm
widget/windows/KeyboardLayout.cpp
widget/windows/KeyboardLayout.h
widget/windows/nsWindow.cpp
widget/windows/nsWindow.h
--- a/widget/windows/KeyboardLayout.cpp
+++ b/widget/windows/KeyboardLayout.cpp
@@ -1981,11 +1981,40 @@ DeadKeyTable::GetCompositeChar(PRUnichar
     if (mTable[index].BaseChar > aBaseChar) {
       break;
     }
   }
 
   return 0;
 }
 
+/*****************************************************************************
+ * mozilla::widget::RedirectedKeyDownMessage
+ *****************************************************************************/
+
+MSG RedirectedKeyDownMessageManager::sRedirectedKeyDownMsg;
+bool RedirectedKeyDownMessageManager::sDefaultPreventedOfRedirectedMsg = false;
+
+// static
+bool
+RedirectedKeyDownMessageManager::IsRedirectedMessage(const MSG& aMsg)
+{
+  return (aMsg.message == WM_KEYDOWN || aMsg.message == WM_SYSKEYDOWN) &&
+         (sRedirectedKeyDownMsg.message == aMsg.message &&
+          WinUtils::GetScanCode(sRedirectedKeyDownMsg.lParam) ==
+            WinUtils::GetScanCode(aMsg.lParam));
+}
+
+// static
+void
+RedirectedKeyDownMessageManager::RemoveNextCharMessage(HWND aWnd)
+{
+  MSG msg;
+  if (WinUtils::PeekMessage(&msg, aWnd, WM_KEYFIRST, WM_KEYLAST,
+                            PM_NOREMOVE | PM_NOYIELD) &&
+      (msg.message == WM_CHAR || msg.message == WM_SYSCHAR)) {
+    WinUtils::GetMessage(&msg, aWnd, msg.message, msg.message);
+  }
+}
+
 } // namespace widget
 } // namespace mozilla
 
--- a/widget/windows/KeyboardLayout.h
+++ b/widget/windows/KeyboardLayout.h
@@ -579,12 +579,90 @@ public:
   }
 
   /**
    * This wraps MapVirtualKeyEx() API with MAPVK_VK_TO_VSC.
    */
   WORD ComputeScanCodeForVirtualKeyCode(uint8_t aVirtualKeyCode) const;
 };
 
+class RedirectedKeyDownMessageManager
+{
+public:
+  /*
+   * If a window receives WM_KEYDOWN message or WM_SYSKEYDOWM message which is
+   * a redirected message, NativeKey::DispatchKeyDownAndKeyPressEvent()
+   * prevents to dispatch NS_KEY_DOWN event because it has been dispatched
+   * before the message was redirected.  However, in some cases, WM_*KEYDOWN
+   * message handler may not handle actually.  Then, the message handler needs
+   * to forget the redirected message and remove WM_CHAR message or WM_SYSCHAR
+   * message for the redirected keydown message.  AutoFlusher class is a helper
+   * class for doing it.  This must be created in the stack.
+   */
+  class MOZ_STACK_CLASS AutoFlusher MOZ_FINAL
+  {
+  public:
+    AutoFlusher(nsWindowBase* aWidget, const MSG &aMsg) :
+      mCancel(!RedirectedKeyDownMessageManager::IsRedirectedMessage(aMsg)),
+      mWidget(aWidget), mMsg(aMsg)
+    {
+    }
+
+    ~AutoFlusher()
+    {
+      if (mCancel) {
+        return;
+      }
+      // Prevent unnecessary keypress event
+      if (!mWidget->Destroyed()) {
+        RedirectedKeyDownMessageManager::RemoveNextCharMessage(mMsg.hwnd);
+      }
+      // Foreget the redirected message
+      RedirectedKeyDownMessageManager::Forget();
+    }
+
+    void Cancel() { mCancel = true; }
+
+  private:
+    bool mCancel;
+    nsRefPtr<nsWindowBase> mWidget;
+    const MSG &mMsg;
+  };
+
+  static void WillRedirect(const MSG& aMsg, bool aDefualtPrevented)
+  {
+    sRedirectedKeyDownMsg = aMsg;
+    sDefaultPreventedOfRedirectedMsg = aDefualtPrevented;
+  }
+
+  static void Forget()
+  {
+    sRedirectedKeyDownMsg.message = WM_NULL;
+  }
+
+  static void PreventDefault() { sDefaultPreventedOfRedirectedMsg = true; }
+  static bool DefaultPrevented() { return sDefaultPreventedOfRedirectedMsg; }
+
+  static bool IsRedirectedMessage(const MSG& aMsg);
+
+  /**
+   * RemoveNextCharMessage() should be called by WM_KEYDOWN or WM_SYSKEYDOWM
+   * message handler.  If there is no WM_(SYS)CHAR message for it, this
+   * method does nothing.
+   * NOTE: WM_(SYS)CHAR message is posted by TranslateMessage() API which is
+   * called in message loop.  So, WM_(SYS)KEYDOWN message should have
+   * WM_(SYS)CHAR message in the queue if the keydown event causes character
+   * input.
+   */
+  static void RemoveNextCharMessage(HWND aWnd);
+
+private:
+  // sRedirectedKeyDownMsg is WM_KEYDOWN message or WM_SYSKEYDOWN message which
+  // is reirected with SendInput() API by
+  // widget::NativeKey::DispatchKeyDownAndKeyPressEvent()
+  static MSG sRedirectedKeyDownMsg;
+  static bool sDefaultPreventedOfRedirectedMsg;
+};
+
 } // namespace widget
 } // namespace mozilla
 
 #endif
--- a/widget/windows/nsWindow.cpp
+++ b/widget/windows/nsWindow.cpp
@@ -226,18 +226,16 @@ bool            nsWindow::sAllowD3D9    
 
 TriStateBool nsWindow::sHasBogusPopupsDropShadowOnMultiMonitor = TRI_UNKNOWN;
 
 // Used in OOPP plugin focus processing.
 const PRUnichar* kOOPPPluginFocusEventId   = L"OOPP Plugin Focus Widget Event";
 uint32_t        nsWindow::sOOPPPluginFocusEvent   =
                   RegisterWindowMessageW(kOOPPPluginFocusEventId);
 
-MSG             nsWindow::sRedirectedKeyDown;
-
 /**************************************************************
  *
  * SECTION: globals variables
  *
  **************************************************************/
 
 static const char *sScreenManagerContractID       = "@mozilla.org/gfx/screenmanager;1";
 
@@ -356,17 +354,17 @@ nsWindow::nsWindow() : nsWindowBase()
       sIsOleInitialized = TRUE;
     }
     NS_ASSERTION(sIsOleInitialized, "***** OLE is not initialized!\n");
     MouseScrollHandler::Initialize();
     // Init titlebar button info for custom frames.
     nsUXThemeData::InitTitlebarInfo();
     // Init theme data
     nsUXThemeData::UpdateNativeThemeInfo();
-    ForgetRedirectedKeyDownMessage();
+    RedirectedKeyDownMessageManager::Forget();
   } // !sInstanceCount
 
   mIdleService = nullptr;
 
   sInstanceCount++;
 }
 
 nsWindow::~nsWindow()
@@ -5099,17 +5097,17 @@ bool nsWindow::ProcessMessage(UINT msg, 
       mmi->ptMaxTrackSize.y = std::min((int32_t)mmi->ptMaxTrackSize.y, mSizeConstraints.mMaxSize.height);
     }
     break;
 
     case WM_SETFOCUS:
       // If previous focused window isn't ours, it must have received the
       // redirected message.  So, we should forget it.
       if (!WinUtils::IsOurProcessWindow(HWND(wParam))) {
-        ForgetRedirectedKeyDownMessage();
+        RedirectedKeyDownMessageManager::Forget();
       }
       if (sJustGotActivate) {
         DispatchFocusToTopLevelWindow(true);
       }
       break;
 
     case WM_KILLFOCUS:
       if (sJustGotDeactivate) {
@@ -5557,35 +5555,16 @@ void nsWindow::PostSleepWakeNotification
   nsCOMPtr<nsIObserverService> observerService =
     mozilla::services::GetObserverService();
   if (observerService)
     observerService->NotifyObservers(nullptr,
       aIsSleepMode ? NS_WIDGET_SLEEP_OBSERVER_TOPIC :
                      NS_WIDGET_WAKE_OBSERVER_TOPIC, nullptr);
 }
 
-// RemoveNextCharMessage() should be called by WM_KEYDOWN or WM_SYSKEYDOWM
-// message handler.  If there is no WM_(SYS)CHAR message for it, this
-// method does nothing.
-// NOTE: WM_(SYS)CHAR message is posted by TranslateMessage() API which is
-// called in message loop.  So, WM_(SYS)KEYDOWN message should have
-// WM_(SYS)CHAR message in the queue if the keydown event causes character
-// input.
-
-/* static */
-void nsWindow::RemoveNextCharMessage(HWND aWnd)
-{
-  MSG msg;
-  if (WinUtils::PeekMessage(&msg, aWnd, WM_KEYFIRST, WM_KEYLAST,
-                            PM_NOREMOVE | PM_NOYIELD) &&
-      (msg.message == WM_CHAR || msg.message == WM_SYSCHAR)) {
-    WinUtils::GetMessage(&msg, aWnd, msg.message, msg.message);
-  }
-}
-
 LRESULT nsWindow::ProcessCharMessage(const MSG &aMsg, bool *aEventDispatched)
 {
   if (IMEHandler::IsComposingOn(this)) {
     IMEHandler::NotifyIME(this, REQUEST_TO_COMMIT_COMPOSITION);
   }
   // These must be checked here too as a lone WM_CHAR could be received
   // if a child window didn't handle it (for example Alt+Space in a content
   // window)
@@ -5606,19 +5585,19 @@ LRESULT nsWindow::ProcessKeyUpMessage(co
   return static_cast<LRESULT>(nativeKey.HandleKeyUpMessage(aEventDispatched));
 }
 
 LRESULT nsWindow::ProcessKeyDownMessage(const MSG &aMsg,
                                         bool *aEventDispatched)
 {
   // If this method doesn't call OnKeyDown(), this method must clean up the
   // redirected message information itself.  For more information, see above
-  // comment of AutoForgetRedirectedKeyDownMessage struct definition in
-  // nsWindow.h.
-  AutoForgetRedirectedKeyDownMessage forgetRedirectedMessage(this, aMsg);
+  // comment of RedirectedKeyDownMessageManager::AutoFlusher class definition
+  // in KeyboardLayout.h.
+  RedirectedKeyDownMessageManager::AutoFlusher redirectedMsgFlusher(this, aMsg);
 
   ModifierKeyState modKeyState;
 
   // Note: the original code passed (HIWORD(lParam)) to OnKeyDown as
   // scan code. However, this breaks Alt+Num pad input.
   // MSDN states the following:
   //  Typically, ToAscii performs the translation based on the
   //  virtual-key code. In some cases, however, bit 15 of the
@@ -5626,17 +5605,17 @@ LRESULT nsWindow::ProcessKeyDownMessage(
   //  press and a key release. The scan code is used for
   //  translating ALT+number key combinations.
 
   LRESULT result = 0;
   if (!IMEHandler::IsComposingOn(this)) {
     result = OnKeyDown(aMsg, modKeyState, aEventDispatched, nullptr);
     // OnKeyDown cleaned up the redirected message information itself, so,
     // we should do nothing.
-    forgetRedirectedMessage.mCancel = true;
+    redirectedMsgFlusher.Cancel();
   }
 
   if (aMsg.wParam == VK_MENU ||
       (aMsg.wParam == VK_F10 && !modKeyState.IsShift())) {
     // We need to let Windows handle this keypress,
     // by returning false, if there's a native menu
     // bar somewhere in our containing window hierarchy.
     // Otherwise we handle the keypress and don't pass
@@ -6330,25 +6309,16 @@ bool nsWindow::OnGesture(WPARAM wParam, 
   }
 
   // Only close this if we process and return true.
   mGesture.CloseGestureInfoHandle((HGESTUREINFO)lParam);
 
   return true; // Handled
 }
 
-/* static */
-bool nsWindow::IsRedirectedKeyDownMessage(const MSG &aMsg)
-{
-  return (aMsg.message == WM_KEYDOWN || aMsg.message == WM_SYSKEYDOWN) &&
-         (sRedirectedKeyDown.message == aMsg.message &&
-          WinUtils::GetScanCode(sRedirectedKeyDown.lParam) ==
-            WinUtils::GetScanCode(aMsg.lParam));
-}
-
 /**
  * nsWindow::OnKeyDown peeks into the message queue and pulls out
  * WM_CHAR messages for processing. During testing we don't want to
  * mess with the real message queue. Instead we pass a
  * pseudo-WM_CHAR-message using this structure, and OnKeyDown will use
  * that as if it was in the message queue, and refrain from actually
  * looking at or touching the message queue.
  */
@@ -6356,82 +6326,81 @@ LRESULT nsWindow::OnKeyDown(const MSG &a
                             const ModifierKeyState &aModKeyState,
                             bool *aEventDispatched,
                             nsFakeCharMessage* aFakeCharMessage)
 {
   KeyboardLayout* keyboardLayout = KeyboardLayout::GetInstance();
   NativeKey nativeKey(this, aMsg, aModKeyState, aFakeCharMessage);
   uint32_t DOMKeyCode = nativeKey.GetDOMKeyCode();
 
-  static bool sRedirectedKeyDownEventPreventedDefault = false;
   bool noDefault;
-  if (aFakeCharMessage || !IsRedirectedKeyDownMessage(aMsg)) {
+  if (aFakeCharMessage ||
+      !RedirectedKeyDownMessageManager::IsRedirectedMessage(aMsg)) {
     bool isIMEEnabled = IMEHandler::IsIMEEnabled(mInputContext);
     bool eventDispatched;
     noDefault = nativeKey.DispatchKeyDownEvent(&eventDispatched);
     if (aEventDispatched) {
       *aEventDispatched = eventDispatched;
     }
     if (!eventDispatched) {
       // If keydown event was not dispatched, keypress event shouldn't be
       // caused with the message.
-      ForgetRedirectedKeyDownMessage();
+      RedirectedKeyDownMessageManager::Forget();
       return 0;
     }
 
     // If IMC wasn't associated to the window but is associated it now (i.e.,
     // focus is moved from a non-editable editor to an editor by keydown
     // event handler), WM_CHAR and WM_SYSCHAR shouldn't cause first character
     // inputting if IME is opened.  But then, we should redirect the native
     // keydown message to IME.
     // However, note that if focus has been already moved to another
     // application, we shouldn't redirect the message to it because the keydown
     // message is processed by us, so, nobody shouldn't process it.
     HWND focusedWnd = ::GetFocus();
     if (!noDefault && !aFakeCharMessage && focusedWnd && !PluginHasFocus() &&
         !isIMEEnabled && IMEHandler::IsIMEEnabled(mInputContext)) {
-      RemoveNextCharMessage(focusedWnd);
+      RedirectedKeyDownMessageManager::RemoveNextCharMessage(focusedWnd);
 
       INPUT keyinput;
       keyinput.type = INPUT_KEYBOARD;
       keyinput.ki.wVk = aMsg.wParam;
       keyinput.ki.wScan = WinUtils::GetScanCode(aMsg.lParam);
       keyinput.ki.dwFlags = KEYEVENTF_SCANCODE;
       if (WinUtils::IsExtendedScanCode(aMsg.lParam)) {
         keyinput.ki.dwFlags |= KEYEVENTF_EXTENDEDKEY;
       }
       keyinput.ki.time = 0;
       keyinput.ki.dwExtraInfo = 0;
 
-      sRedirectedKeyDownEventPreventedDefault = noDefault;
-      sRedirectedKeyDown = aMsg;
+      RedirectedKeyDownMessageManager::WillRedirect(aMsg, noDefault);
 
       ::SendInput(1, &keyinput, sizeof(keyinput));
 
       // Return here.  We shouldn't dispatch keypress event for this WM_KEYDOWN.
       // If it's needed, it will be dispatched after next (redirected)
       // WM_KEYDOWN.
       return true;
     }
 
     if (mOnDestroyCalled) {
       // If this was destroyed by the keydown event handler, we shouldn't
       // dispatch keypress event on this window.
       return true;
     }
   } else {
-    noDefault = sRedirectedKeyDownEventPreventedDefault;
+    noDefault = RedirectedKeyDownMessageManager::DefaultPrevented();
     // If this is redirected keydown message, we have dispatched the keydown
     // event already.
     if (aEventDispatched) {
       *aEventDispatched = true;
     }
   }
 
-  ForgetRedirectedKeyDownMessage();
+  RedirectedKeyDownMessageManager::Forget();
 
   // If the key was processed by IME, we shouldn't dispatch keypress event.
   if (aMsg.wParam == VK_PROCESSKEY) {
     return noDefault;
   }
 
   // If we won't be getting a WM_CHAR, WM_SYSCHAR or WM_DEADCHAR, synthesize a keypress
   // for almost all keys
--- a/widget/windows/nsWindow.h
+++ b/widget/windows/nsWindow.h
@@ -320,37 +320,31 @@ protected:
 
   /**
    * Event processing helpers
    */
   void                    DispatchFocusToTopLevelWindow(bool aIsActivate);
   bool                    DispatchStandardEvent(uint32_t aMsg);
   bool                    DispatchCommandEvent(uint32_t aEventCommand);
   void                    RelayMouseEvent(UINT aMsg, WPARAM wParam, LPARAM lParam);
-  static void             RemoveNextCharMessage(HWND aWnd);
   virtual bool            ProcessMessage(UINT msg, WPARAM &wParam,
                                          LPARAM &lParam, LRESULT *aRetValue);
   bool                    ProcessMessageForPlugin(const MSG &aMsg,
                                                   LRESULT *aRetValue, bool &aCallDefWndProc);
   LRESULT                 ProcessCharMessage(const MSG &aMsg,
                                              bool *aEventDispatched);
   LRESULT                 ProcessKeyUpMessage(const MSG &aMsg,
                                               bool *aEventDispatched);
   LRESULT                 ProcessKeyDownMessage(const MSG &aMsg,
                                                 bool *aEventDispatched);
   static bool             EventIsInsideWindow(UINT Msg, nsWindow* aWindow);
   // Convert nsEventStatus value to a windows boolean
   static bool             ConvertStatus(nsEventStatus aStatus);
   static void             PostSleepWakeNotification(const bool aIsSleepMode);
   int32_t                 ClientMarginHitTestPoint(int32_t mx, int32_t my);
-  static bool             IsRedirectedKeyDownMessage(const MSG &aMsg);
-  static void             ForgetRedirectedKeyDownMessage()
-  {
-    sRedirectedKeyDown.message = WM_NULL;
-  }
 
   /**
    * Event handlers
    */
   virtual void            OnDestroy();
   virtual bool            OnMove(int32_t aX, int32_t aY);
   virtual bool            OnResize(nsIntRect &aWindowRect);
   LRESULT                 OnKeyDown(const MSG &aMsg,
@@ -538,56 +532,18 @@ protected:
   // True if the taskbar (possibly through the tab preview) tells us that the
   // icon has been created on the taskbar.
   bool                  mHasTaskbarIconBeenCreated;
 
   // The point in time at which the last paint completed. We use this to avoid
   //  painting too rapidly in response to frequent input events.
   TimeStamp mLastPaintEndTime;
 
-  // sRedirectedKeyDown is WM_KEYDOWN message or WM_SYSKEYDOWN message which
-  // was reirected to SendInput() API by OnKeyDown().
-  static MSG            sRedirectedKeyDown;
-
   static bool sNeedsToInitMouseWheelSettings;
   static void InitMouseWheelScrollData();
-
-  // If a window receives WM_KEYDOWN message or WM_SYSKEYDOWM message which is
-  // redirected message, OnKeyDowm() prevents to dispatch NS_KEY_DOWN event
-  // because it has been dispatched before the message was redirected.
-  // However, in some cases, ProcessKeyDownMessage() doesn't call OnKeyDown().
-  // Then, ProcessKeyDownMessage() needs to forget the redirected message and
-  // remove WM_CHAR message or WM_SYSCHAR message for the redirected keydown
-  // message.  AutoForgetRedirectedKeyDownMessage struct is a helper struct
-  // for doing that.  This must be created in stack.
-  struct AutoForgetRedirectedKeyDownMessage
-  {
-    AutoForgetRedirectedKeyDownMessage(nsWindow* aWindow, const MSG &aMsg) :
-      mCancel(!nsWindow::IsRedirectedKeyDownMessage(aMsg)),
-      mWindow(aWindow), mMsg(aMsg)
-    {
-    }
-
-    ~AutoForgetRedirectedKeyDownMessage()
-    {
-      if (mCancel) {
-        return;
-      }
-      // Prevent unnecessary keypress event
-      if (!mWindow->mOnDestroyCalled) {
-        nsWindow::RemoveNextCharMessage(mWindow->mWnd);
-      }
-      // Foreget the redirected message
-      nsWindow::ForgetRedirectedKeyDownMessage();
-    }
-
-    bool mCancel;
-    nsRefPtr<nsWindow> mWindow;
-    const MSG &mMsg;
-  };
 };
 
 /**
  * A child window is a window with different style.
  */
 class ChildWindow : public nsWindow {
 
 public: