Bug 593372 - Part 4: Work around the Elantech v8 driver's erroneous message timestamps for zoom gestures (v2.1) r=jmathies a=blocking-final
authorEhsan Akhgari <ehsan@mozilla.com>
Tue, 08 Feb 2011 18:07:00 -0500
changeset 62186 d2db6c6be747f9228e66b8d2b66d23c88dff2732
parent 62185 0da0c99b690d1f222e5676d04706f8eeab93a332
child 62187 ca548ef9d8c653adddc82177befb141e27c8c35f
child 62213 8ba0d8f0efb2b6e3a6a6b94c7b3984dcff36ba57
push id18633
push usereakhgari@mozilla.com
push dateTue, 08 Feb 2011 23:07:49 +0000
treeherdermozilla-central@d2db6c6be747 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjmathies, blocking-final
bugs593372
milestone2.0b12pre
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 593372 - Part 4: Work around the Elantech v8 driver's erroneous message timestamps for zoom gestures (v2.1) r=jmathies a=blocking-final
widget/src/windows/nsWindow.cpp
widget/src/windows/nsWindow.h
--- a/widget/src/windows/nsWindow.cpp
+++ b/widget/src/windows/nsWindow.cpp
@@ -4648,16 +4648,34 @@ nsWindow::ProcessMessageForPlugin(const 
   DispatchPendingEvents();
   return PR_TRUE;
 }
 
 // The main windows message processing method.
 PRBool nsWindow::ProcessMessage(UINT msg, WPARAM &wParam, LPARAM &lParam,
                                 LRESULT *aRetValue)
 {
+  // For the Elantech Touchpad Zoom Gesture Hack, we should check that the
+  // system time (32-bit milliseconds) hasn't wrapped around.  Otherwise we
+  // might get into the situation where wheel events for the next 50 days of
+  // system uptime are assumed to be Ctrl+Wheel events.  (It is unlikely that
+  // we would get into that state, because the system would already need to be
+  // up for 50 days and the Control key message would need to be processed just
+  // before the system time overflow and the wheel message just after.)
+  //
+  // We also take the chance to reset mAssumeWheelIsZoomUntil if we simply have
+  // passed that time.
+  if (mAssumeWheelIsZoomUntil) {
+    DWORD msgTime = ::GetMessageTime();
+    if (mAssumeWheelIsZoomUntil >= 0x80000000 && msgTime < 0x8000000 ||
+        mAssumeWheelIsZoomUntil < msgTime) {
+      mAssumeWheelIsZoomUntil = 0;
+    }
+  }
+
   // (Large blocks of code should be broken out into OnEvent handlers.)
   if (mWindowHook.Notify(mWnd, msg, wParam, lParam, aRetValue))
     return PR_TRUE;
 
 #if defined(EVENT_DEBUG_OUTPUT)
   // First param shows all events, second param indicates whether
   // to show mouse move events. See nsWindowDbg for details.
   PrintEvent(msg, SHOW_REPEAT_EVENTS, SHOW_MOUSEMOVE_EVENTS);
@@ -5022,16 +5040,17 @@ PRBool nsWindow::ProcessMessage(UINT msg
       DispatchPendingEvents();
     }
     break;
 
     case WM_SYSKEYUP:
     case WM_KEYUP:
     {
       MSG nativeMsg = InitMSG(msg, wParam, lParam);
+      nativeMsg.time = ::GetMessageTime();
       result = ProcessKeyUpMessage(nativeMsg, nsnull);
       DispatchPendingEvents();
     }
     break;
 
     case WM_SYSKEYDOWN:
     case WM_KEYDOWN:
     {
@@ -6701,18 +6720,28 @@ PRBool nsWindow::OnMouseWheel(UINT msg, 
   }
 
 #ifdef MOZ_IPC
   // The event may go to a plug-in which already dispatched this message.
   // Then, the event can cause deadlock.  We should unlock the sender here.
   ::ReplyMessage(isVertical ? 0 : TRUE);
 #endif
 
+  // Assume the Control key is down if the Elantech touchpad has sent the
+  // mis-ordered WM_KEYDOWN/WM_MOUSEWHEEL messages.  (See the comment in
+  // OnKeyUp.)
+  PRBool isControl;
+  if (mAssumeWheelIsZoomUntil && ::GetMessageTime() < mAssumeWheelIsZoomUntil) {
+    isControl = PR_TRUE;
+  } else {
+    isControl = IS_VK_DOWN(NS_VK_CONTROL);
+  }
+
   scrollEvent.isShift   = IS_VK_DOWN(NS_VK_SHIFT);
-  scrollEvent.isControl = IS_VK_DOWN(NS_VK_CONTROL);
+  scrollEvent.isControl = isControl;
   scrollEvent.isMeta    = PR_FALSE;
   scrollEvent.isAlt     = IS_VK_DOWN(NS_VK_ALT);
   InitEvent(scrollEvent);
   if (nsnull != mEventCallback) {
     result = DispatchWindowEvent(&scrollEvent);
   }
   // Note that we should return zero if we process WM_MOUSEWHEEL.
   // But if we process WM_MOUSEHWHEEL, we should return non-zero.
@@ -7157,16 +7186,35 @@ LRESULT nsWindow::OnKeyDown(const MSG &a
 LRESULT nsWindow::OnKeyUp(const MSG &aMsg,
                           nsModifierKeyState &aModKeyState,
                           PRBool *aEventDispatched)
 {
   UINT virtualKeyCode = aMsg.wParam;
 
   if (sUseElantechGestureHacks) {
     PerformElantechSwipeGestureHack(virtualKeyCode, aModKeyState);
+
+    // Version 8 of the Elantech touchpad driver sends these messages for
+    // zoom gestures:
+    //
+    //   WM_KEYDOWN    virtual_key = 0xCC        time = 10
+    //   WM_KEYDOWN    virtual_key = VK_CONTROL  time = 10
+    //   WM_MOUSEWHEEL                           time = ::GetTickCount()
+    //   WM_KEYUP      virtual_key = VK_CONTROL  time = 10
+    //   WM_KEYUP      virtual_key = 0xCC        time = 10
+    //
+    // The result of this is that we process all of the WM_KEYDOWN/WM_KEYUP
+    // messages first because their timestamps make them appear to have
+    // been sent before the WM_MOUSEWHEEL message.  To work around this,
+    // we store the current time when we process the WM_KEYUP message and
+    // assume that any WM_MOUSEWHEEL message with a timestamp before that
+    // time is one that should be processed as if the Control key was down.
+    if (virtualKeyCode == VK_CONTROL && aMsg.time == 10) {
+      mAssumeWheelIsZoomUntil = ::GetTickCount();
+    }
   }
 
   PR_LOG(gWindowsLog, PR_LOG_ALWAYS,
          ("nsWindow::OnKeyUp VK=%d\n", virtualKeyCode));
 
   if (!nsIMM32Handler::IsComposingOn(this)) {
     virtualKeyCode = MapFromNativeToDOM(virtualKeyCode);
   }
--- a/widget/src/windows/nsWindow.h
+++ b/widget/src/windows/nsWindow.h
@@ -526,16 +526,17 @@ protected:
   DWORD_PTR             mOldExStyle;
   HIMC                  mOldIMC;
   IMEContext            mIMEContext;
   nsNativeDragTarget*   mNativeDragTarget;
   HKL                   mLastKeyboardLayout;
   nsPopupType           mPopupType;
   nsSizeMode            mOldSizeMode;
   WindowHook            mWindowHook;
+  DWORD                 mAssumeWheelIsZoomUntil;
   static PRUint32       sInstanceCount;
   static TriStateBool   sCanQuit;
   static nsWindow*      sCurrentWindow;
   static BOOL           sIsOleInitialized;
   static HCURSOR        sHCursor;
   static imgIContainer* sCursorImgContainer;
   static PRBool         sSwitchKeyboardLayout;
   static PRBool         sJustGotDeactivate;