From a60c46de7f784321bea326ad5b962f79aa0c9ecd Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Thu, 22 Mar 2012 09:59:12 +0900 Subject: [PATCH] Bug 672175 part.16 Implement nsIWidget::SynthesizeNativeMouseScrollEvent() on Windows r=jimm --- dom/interfaces/base/nsIDOMWindowUtils.idl | 26 ++ widget/windows/WinMouseScrollHandler.cpp | 308 +++++++++++++++++++++- widget/windows/WinMouseScrollHandler.h | 104 ++++++++ widget/windows/nsAppShell.cpp | 15 ++ widget/windows/nsWindow.cpp | 16 ++ widget/windows/nsWindow.h | 10 +- widget/windows/nsWindowDefs.h | 3 + 7 files changed, 468 insertions(+), 14 deletions(-) diff --git a/dom/interfaces/base/nsIDOMWindowUtils.idl b/dom/interfaces/base/nsIDOMWindowUtils.idl index 4282283ac94a..b90c2b57e8b9 100644 --- a/dom/interfaces/base/nsIDOMWindowUtils.idl +++ b/dom/interfaces/base/nsIDOMWindowUtils.idl @@ -377,6 +377,10 @@ interface nsIDOMWindowUtils : nsISupports { * privileges. * * NOTE: The synthesized native event may be fired asynchronously. + * + * @param aNativeMessage + * On Windows: WM_MOUSEWHEEL (0x020A), WM_MOUSEHWHEEL(0x020E), + * WM_VSCROLL (0x0115) or WM_HSCROLL (0x114). */ void sendNativeMouseScrollEvent(in long aScreenX, in long aScreenY, @@ -388,6 +392,28 @@ interface nsIDOMWindowUtils : nsISupports { in unsigned long aAdditionalFlags, in nsIDOMElement aElement); + /** + * The values of aAdditionalFlags. + */ + + /** + * If MOUSESCROLL_PREFER_WIDGET_AT_POINT is set, widget will dispatch + * the event to a widget which is under the cursor. Otherwise, dispatch to + * a default target on the platform. E.g., on Windows, it's focused window. + */ + const unsigned long MOUSESCROLL_PREFER_WIDGET_AT_POINT = 0x00000001; + + /** + * The platform specific values of aAdditionalFlags. Must be over 0x00010000. + */ + + /** + * If MOUSESCROLL_WIN_SCROLL_LPARAM_NOT_NULL is set and aNativeMessage is + * WM_VSCROLL or WM_HSCROLL, widget will set the window handle to the lParam + * instead of NULL. + */ + const unsigned long MOUSESCROLL_WIN_SCROLL_LPARAM_NOT_NULL = 0x00010000; + /** * See nsIWidget::ActivateNativeMenuItemAt * diff --git a/widget/windows/WinMouseScrollHandler.cpp b/widget/windows/WinMouseScrollHandler.cpp index 7d2a4dad3112..0d9a650fce69 100644 --- a/widget/windows/WinMouseScrollHandler.cpp +++ b/widget/windows/WinMouseScrollHandler.cpp @@ -13,6 +13,7 @@ #include "nsWindow.h" #include "WinUtils.h" #include "nsGkAtoms.h" +#include "nsIDOMWindowUtils.h" #include "mozilla/Preferences.h" @@ -79,6 +80,20 @@ bool MouseScrollHandler::Device::SetPoint::sMightBeUsing = false; * ******************************************************************************/ +/* static */ +POINTS +MouseScrollHandler::GetCurrentMessagePos() +{ + if (SynthesizingEvent::IsSynthesizing()) { + return sInstance->mSynthesizingEvent->GetCursorPoint(); + } + DWORD pos = ::GetMessagePos(); + return MAKEPOINTS(pos); +} + +// Get rid of the GetMessagePos() API. +#define GetMessagePos() + /* static */ void MouseScrollHandler::Initialize() @@ -109,7 +124,9 @@ MouseScrollHandler::GetInstance() return sInstance; } -MouseScrollHandler::MouseScrollHandler() +MouseScrollHandler::MouseScrollHandler() : + mIsWaitingInternalMessage(false), + mSynthesizingEvent(nsnull) { PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS, ("MouseScroll: Creating an instance, this=%p, sInstance=%p", @@ -121,6 +138,8 @@ MouseScrollHandler::~MouseScrollHandler() PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS, ("MouseScroll: Destroying an instance, this=%p, sInstance=%p", this, sInstance)); + + delete mSynthesizingEvent; } /* static */ @@ -146,6 +165,7 @@ MouseScrollHandler::ProcessMessage(nsWindow* aWindow, UINT msg, case WM_MOUSEHWHEEL: GetInstance()-> ProcessNativeMouseWheelMessage(aWindow, msg, wParam, lParam); + sInstance->mSynthesizingEvent->NotifyNativeMessageHandlingFinished(); // We don't need to call next wndproc for WM_MOUSEWHEEL and // WM_MOUSEHWHEEL. We should consume them always. If the messages // would be handled by our window again, it caused making infinite @@ -158,12 +178,14 @@ MouseScrollHandler::ProcessMessage(nsWindow* aWindow, UINT msg, case WM_VSCROLL: aEatMessage = GetInstance()->ProcessNativeScrollMessage(aWindow, msg, wParam, lParam); + sInstance->mSynthesizingEvent->NotifyNativeMessageHandlingFinished(); *aRetValue = 0; return true; case MOZ_WM_MOUSEVWHEEL: case MOZ_WM_MOUSEHWHEEL: GetInstance()->HandleMouseWheelMessage(aWindow, msg, wParam, lParam); + sInstance->mSynthesizingEvent->NotifyInternalMessageHandlingFinished(); // Doesn't need to call next wndproc for internal wheel message. aEatMessage = true; return true; @@ -172,6 +194,7 @@ MouseScrollHandler::ProcessMessage(nsWindow* aWindow, UINT msg, case MOZ_WM_VSCROLL: GetInstance()-> HandleScrollMessageAsMouseWheelMessage(aWindow, msg, wParam, lParam); + sInstance->mSynthesizingEvent->NotifyInternalMessageHandlingFinished(); // Doesn't need to call next wndproc for internal scroll message. aEatMessage = true; return true; @@ -197,6 +220,81 @@ MouseScrollHandler::ProcessMessage(nsWindow* aWindow, UINT msg, } } +/* static */ +nsresult +MouseScrollHandler::SynthesizeNativeMouseScrollEvent(nsWindow* aWindow, + const nsIntPoint& aPoint, + PRUint32 aNativeMessage, + PRInt32 aDelta, + PRUint32 aModifierFlags, + PRUint32 aAdditionalFlags) +{ + bool useFocusedWindow = + !(aAdditionalFlags & nsIDOMWindowUtils::MOUSESCROLL_PREFER_WIDGET_AT_POINT); + + POINT pt; + pt.x = aPoint.x; + pt.y = aPoint.y; + + HWND target = useFocusedWindow ? ::WindowFromPoint(pt) : ::GetFocus(); + NS_ENSURE_TRUE(target, NS_ERROR_FAILURE); + + WPARAM wParam = 0; + LPARAM lParam = 0; + switch (aNativeMessage) { + case WM_MOUSEWHEEL: + case WM_MOUSEHWHEEL: { + lParam = MAKELPARAM(pt.x, pt.y); + WORD mod = 0; + if (aModifierFlags & (nsIWidget::CTRL_L | nsIWidget::CTRL_R)) { + mod |= MK_CONTROL; + } + if (aModifierFlags & (nsIWidget::SHIFT_L | nsIWidget::SHIFT_R)) { + mod |= MK_SHIFT; + } + wParam = MAKEWPARAM(mod, aDelta); + break; + } + case WM_VSCROLL: + case WM_HSCROLL: + lParam = (aAdditionalFlags & + nsIDOMWindowUtils::MOUSESCROLL_WIN_SCROLL_LPARAM_NOT_NULL) ? + reinterpret_cast(target) : NULL; + wParam = aDelta; + break; + default: + return NS_ERROR_INVALID_ARG; + } + + // Ensure to make the instance. + GetInstance(); + + BYTE kbdState[256]; + memset(kbdState, 0, sizeof(kbdState)); + + nsAutoTArray keySequence; + nsWindow::SetupKeyModifiersSequence(&keySequence, aModifierFlags); + + for (PRUint32 i = 0; i < keySequence.Length(); ++i) { + PRUint8 key = keySequence[i].mGeneral; + PRUint8 keySpecific = keySequence[i].mSpecific; + kbdState[key] = 0x81; // key is down and toggled on if appropriate + if (keySpecific) { + kbdState[keySpecific] = 0x81; + } + } + + if (!sInstance->mSynthesizingEvent) { + sInstance->mSynthesizingEvent = new SynthesizingEvent(); + } + + POINTS pts; + pts.x = static_cast(pt.x); + pts.y = static_cast(pt.y); + return sInstance->mSynthesizingEvent-> + Synthesize(pts, target, aNativeMessage, wParam, lParam, kbdState); +} + /* static */ bool MouseScrollHandler::DispatchEvent(nsWindow* aWindow, nsGUIEvent& aEvent) @@ -204,6 +302,28 @@ MouseScrollHandler::DispatchEvent(nsWindow* aWindow, nsGUIEvent& aEvent) return aWindow->DispatchWindowEvent(&aEvent); } +/* static */ +void +MouseScrollHandler::InitEvent(nsWindow* aWindow, + nsGUIEvent& aEvent, + nsIntPoint* aPoint) +{ + NS_ENSURE_TRUE(aWindow, ); + nsIntPoint point; + if (aPoint) { + point = *aPoint; + } else { + POINTS pts = GetCurrentMessagePos(); + POINT pt; + pt.x = pts.x; + pt.y = pts.y; + ::ScreenToClient(aWindow->GetWindowHandle(), &pt); + point.x = pt.x; + point.y = pt.y; + } + aWindow->InitEvent(aEvent, &point); +} + /* static */ nsModifierKeyState MouseScrollHandler::GetModifierKeyState(UINT aMessage) @@ -231,11 +351,10 @@ MouseScrollHandler::ComputeMessagePos(UINT aMessage, ("MouseScroll::ComputeMessagePos: Using ::GetCursorPos()")); ::GetCursorPos(&point); } else { - DWORD dwPoints = ::GetMessagePos(); - point.x = GET_X_LPARAM(dwPoints); - point.y = GET_Y_LPARAM(dwPoints); + POINTS pts = GetCurrentMessagePos(); + point.x = pts.x; + point.y = pts.y; } - return point; } @@ -261,7 +380,7 @@ MouseScrollHandler::GetScrollTargetInfo( } nsMouseScrollEvent testEvent(true, NS_MOUSE_SCROLL, aWindow); - aWindow->InitEvent(testEvent); + InitEvent(aWindow, testEvent); aModifierKeyState.InitInputEvent(testEvent); testEvent.scrollFlags = aEventInfo.GetScrollFlags(); @@ -272,7 +391,7 @@ MouseScrollHandler::GetScrollTargetInfo( } nsQueryContentEvent queryEvent(true, NS_QUERY_SCROLL_TARGET_INFO, aWindow); - aWindow->InitEvent(queryEvent); + InitEvent(aWindow, queryEvent); queryEvent.InitForQueryScrollTargetInfo(&testEvent); DispatchEvent(aWindow, queryEvent); @@ -330,6 +449,11 @@ MouseScrollHandler::ProcessNativeMouseWheelMessage(nsWindow* aWindow, WPARAM aWParam, LPARAM aLParam) { + if (SynthesizingEvent::IsSynthesizing()) { + mSynthesizingEvent->NativeMessageReceived(aWindow, aMessage, + aWParam, aLParam); + } + POINT point = ComputeMessagePos(aMessage, aWParam, aLParam); PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS, @@ -408,6 +532,7 @@ MouseScrollHandler::ProcessNativeMouseWheelMessage(nsWindow* aWindow, ("MouseScroll::ProcessNativeMouseWheelMessage: Succeeded, " "Posting internal message to an nsWindow (%p)...", destWindow)); + mIsWaitingInternalMessage = true; UINT internalMessage = WinUtils::GetInternalMessage(aMessage); ::PostMessage(destWindow->GetWindowHandle(), internalMessage, aWParam, aLParam); @@ -447,6 +572,7 @@ MouseScrollHandler::ProcessNativeMouseWheelMessage(nsWindow* aWindow, "Posting internal message to an nsWindow (%p) which is parent of this " "plugin window...", destWindow)); + mIsWaitingInternalMessage = true; UINT internalMessage = WinUtils::GetInternalMessage(aMessage); ::PostMessage(destWindow->GetWindowHandle(), internalMessage, aWParam, aLParam); @@ -475,6 +601,11 @@ MouseScrollHandler::ProcessNativeScrollMessage(nsWindow* aWindow, return true; } + if (SynthesizingEvent::IsSynthesizing()) { + mSynthesizingEvent->NativeMessageReceived(aWindow, aMessage, + aWParam, aLParam); + } + PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS, ("MouseScroll::ProcessNativeScrollMessage: aWindow=%p, " "aMessage=%s, wParam=0x%08X, lParam=0x%08X", @@ -537,6 +668,8 @@ MouseScrollHandler::HandleMouseWheelMessage(nsWindow* aWindow, aWindow, aMessage == MOZ_WM_MOUSEVWHEEL ? "V" : "H", aWParam, aLParam)); + mIsWaitingInternalMessage = false; + EventInfo eventInfo(aWindow, WinUtils::GetNativeMessage(aMessage), aWParam, aLParam); if (!eventInfo.CanDispatchMouseScrollEvent()) { @@ -623,6 +756,8 @@ MouseScrollHandler::HandleScrollMessageAsMouseWheelMessage(nsWindow* aWindow, "HandleScrollMessageAsMouseWheelMessage must be called with " "MOZ_WM_VSCROLL or MOZ_WM_HSCROLL"); + mIsWaitingInternalMessage = false; + nsModifierKeyState modKeyState = GetModifierKeyState(aMessage); nsMouseScrollEvent scrollEvent(true, NS_MOUSE_SCROLL, aWindow); @@ -647,7 +782,7 @@ MouseScrollHandler::HandleScrollMessageAsMouseWheelMessage(nsWindow* aWindow, // XXX Current mouse position may not be same as when the original message // is received. We need to know the actual mouse cursor position when // the original message was received. - aWindow->InitEvent(scrollEvent); + InitEvent(aWindow, scrollEvent); PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS, ("MouseScroll::HandleScrollMessageAsMouseWheelMessage: aWindow=%p, " @@ -784,7 +919,7 @@ MouseScrollHandler::LastEventInfo::InitMouseScrollEvent( // XXX Why don't we use lParam value? We should use lParam value because // our internal message is always posted by original message handler. // So, GetMessagePos() may return different cursor position. - aWindow->InitEvent(aMouseScrollEvent); + InitEvent(aWindow, aMouseScrollEvent); aModKeyState.InitInputEvent(aMouseScrollEvent); @@ -856,7 +991,7 @@ MouseScrollHandler::LastEventInfo::InitMousePixelScrollEvent( // XXX Why don't we use lParam value? We should use lParam value because // our internal message is always posted by original message handler. // So, GetMessagePos() may return different cursor position. - aWindow->InitEvent(aPixelScrollEvent); + InitEvent(aWindow, aPixelScrollEvent); aModKeyState.InitInputEvent(aPixelScrollEvent); @@ -1217,7 +1352,7 @@ MouseScrollHandler::Device::Elantech::HandleKeyMessage(nsWindow* aWindow, nsCommandEvent commandEvent(true, nsGkAtoms::onAppCommand, (aWParam == VK_NEXT) ? nsGkAtoms::Forward : nsGkAtoms::Back, aWindow); - aWindow->InitEvent(commandEvent); + InitEvent(aWindow, commandEvent); MouseScrollHandler::DispatchEvent(aWindow, commandEvent); } #ifdef PR_LOGGING @@ -1406,7 +1541,8 @@ MouseScrollHandler::Device::SetPoint::IsGetMessagePosResponseValid( return false; } - DWORD messagePos = ::GetMessagePos(); + POINTS pts = MouseScrollHandler::GetCurrentMessagePos(); + LPARAM messagePos = MAKELPARAM(pts.x, pts.y); // XXX We should check whether SetPoint is installed or not by registry. @@ -1418,7 +1554,7 @@ MouseScrollHandler::Device::SetPoint::IsGetMessagePosResponseValid( // But ::GetMessagePos() API always returns (0, 0) for them, even if the // actual mouse cursor isn't 0,0. Therefore, we cannot trust the result of // ::GetMessagePos API if the sender is SetPoint. - if (!sMightBeUsing && !aLParam && (DWORD)aLParam != messagePos && + if (!sMightBeUsing && !aLParam && aLParam != messagePos && ::InSendMessage()) { sMightBeUsing = true; PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS, @@ -1435,5 +1571,151 @@ MouseScrollHandler::Device::SetPoint::IsGetMessagePosResponseValid( return (sMightBeUsing && !aLParam && !messagePos); } +/****************************************************************************** + * + * SynthesizingEvent + * + ******************************************************************************/ + +/* static */ +bool +MouseScrollHandler::SynthesizingEvent::IsSynthesizing() +{ + return MouseScrollHandler::sInstance && + MouseScrollHandler::sInstance->mSynthesizingEvent && + MouseScrollHandler::sInstance->mSynthesizingEvent->mStatus != + NOT_SYNTHESIZING; +} + +nsresult +MouseScrollHandler::SynthesizingEvent::Synthesize(const POINTS& aCursorPoint, + HWND aWnd, + UINT aMessage, + WPARAM aWParam, + LPARAM aLParam, + const BYTE (&aKeyStates)[256]) +{ + PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS, + ("MouseScrollHandler::SynthesizingEvent::Synthesize(): aCursorPoint: { " + "x: %d, y: %d }, aWnd=0x%X, aMessage=0x%04X, aWParam=0x%08X, " + "aLParam=0x%08X, IsSynthesized()=%s, mStatus=%s", + aCursorPoint.x, aCursorPoint.y, aWnd, aMessage, aWParam, aLParam, + GetBoolName(IsSynthesizing()), GetStatusName())); + + if (IsSynthesizing()) { + return NS_ERROR_NOT_AVAILABLE; + } + + ::GetKeyboardState(mOriginalKeyState); + + // Note that we cannot use ::SetCursorPos() because it works asynchronously. + // We should SEND the message for reducing the possibility of receiving + // unexpected message which were not sent from here. + mCursorPoint = aCursorPoint; + + mWnd = aWnd; + mMessage = aMessage; + mWParam = aWParam; + mLParam = aLParam; + + memcpy(mKeyState, aKeyStates, sizeof(mKeyState)); + ::SetKeyboardState(mKeyState); + + mStatus = SENDING_MESSAGE; + + // Don't assume that aWnd is always managed by nsWindow. It might be + // a plugin window. + ::SendMessage(aWnd, aMessage, aWParam, aLParam); + + return NS_OK; +} + +void +MouseScrollHandler::SynthesizingEvent::NativeMessageReceived(nsWindow* aWindow, + UINT aMessage, + WPARAM aWParam, + LPARAM aLParam) +{ + if (mStatus == SENDING_MESSAGE && mMessage == aMessage && + mWParam == aWParam && mLParam == aLParam) { + mStatus = NATIVE_MESSAGE_RECEIVED; + if (aWindow && aWindow->GetWindowHandle() == mWnd) { + return; + } + // If the target window is not ours and received window is our plugin + // window, it comes from child window of the plugin. + if (aWindow && aWindow->GetWindowType() == eWindowType_plugin && + !WinUtils::GetNSWindowPtr(mWnd)) { + return; + } + // Otherwise, the message may not be sent by us. + } + + PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS, + ("MouseScrollHandler::SynthesizingEvent::NativeMessageReceived(): " + "aWindow=%p, aWindow->GetWindowHandle()=0x%X, mWnd=0x%X, " + "aMessage=0x%04X, aWParam=0x%08X, aLParam=0x%08X, mStatus=%s", + aWindow, aWindow ? aWindow->GetWindowHandle() : 0, mWnd, + aMessage, aWParam, aLParam, GetStatusName())); + + // We failed to receive our sent message, we failed to do the job. + Finish(); + + return; +} + +void +MouseScrollHandler::SynthesizingEvent::NotifyNativeMessageHandlingFinished() +{ + if (!IsSynthesizing()) { + return; + } + + PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS, + ("MouseScrollHandler::SynthesizingEvent::" + "NotifyNativeMessageHandlingFinished(): IsWaitingInternalMessage=%s", + GetBoolName(MouseScrollHandler::IsWaitingInternalMessage()))); + + if (MouseScrollHandler::IsWaitingInternalMessage()) { + mStatus = INTERNAL_MESSAGE_POSTED; + return; + } + + // If the native message handler didn't post our internal message, + // we our job is finished. + // TODO: When we post the message to plugin window, there is remaning job. + Finish(); +} + +void +MouseScrollHandler::SynthesizingEvent::NotifyInternalMessageHandlingFinished() +{ + if (!IsSynthesizing()) { + return; + } + + PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS, + ("MouseScrollHandler::SynthesizingEvent::" + "NotifyInternalMessageHandlingFinished()")); + + Finish(); +} + +void +MouseScrollHandler::SynthesizingEvent::Finish() +{ + if (!IsSynthesizing()) { + return; + } + + PR_LOG(gMouseScrollLog, PR_LOG_ALWAYS, + ("MouseScrollHandler::SynthesizingEvent::Finish()")); + + // Restore the original key state. + ::SetKeyboardState(mOriginalKeyState); + + mStatus = NOT_SYNTHESIZING; +} + } // namespace widget } // namespace mozilla diff --git a/widget/windows/WinMouseScrollHandler.h b/widget/windows/WinMouseScrollHandler.h index d5d1901885f6..fccbb1c06c2e 100644 --- a/widget/windows/WinMouseScrollHandler.h +++ b/widget/windows/WinMouseScrollHandler.h @@ -16,6 +16,7 @@ class nsWindow; class nsGUIEvent; class nsMouseScrollEvent; +struct nsIntPoint; struct nsModifierKeyState; namespace mozilla { @@ -35,10 +36,33 @@ public: LRESULT *aRetValue, bool &aEatMessage); + /** + * See nsIWidget::SynthesizeNativeMouseScrollEvent() for the detail about + * this method. + */ + static nsresult SynthesizeNativeMouseScrollEvent(nsWindow* aWindow, + const nsIntPoint& aPoint, + PRUint32 aNativeMessage, + PRInt32 aDelta, + PRUint32 aModifierFlags, + PRUint32 aAdditionalFlags); + + /** + * IsWaitingInternalMessage() returns true if MouseScrollHandler posted + * an internal message for a native mouse wheel message and has not + * received it. Otherwise, false. + */ + static bool IsWaitingInternalMessage() + { + return sInstance && sInstance->mIsWaitingInternalMessage; + } + private: MouseScrollHandler(); ~MouseScrollHandler(); + bool mIsWaitingInternalMessage; + static MouseScrollHandler* sInstance; /** @@ -48,6 +72,14 @@ private: */ static bool DispatchEvent(nsWindow* aWindow, nsGUIEvent& aEvent); + /** + * InitEvent() initializes the aEvent. If aPoint is null, the result of + * GetCurrentMessagePos() will be used. + */ + static void InitEvent(nsWindow* aWindow, + nsGUIEvent& aEvent, + nsIntPoint* aPoint = nsnull); + /** * GetModifierKeyState() returns current modifier key state. * Note that some devices need some hack for the modifier key state. @@ -57,6 +89,14 @@ private: */ static nsModifierKeyState GetModifierKeyState(UINT aMessage); + /** + * MozGetMessagePos() returns the mouse cursor position when GetMessage() + * was called last time. However, if we're sending a native message, + * this returns the specified cursor position by + * SynthesizeNativeMouseScrollEvent(). + */ + static POINTS GetCurrentMessagePos(); + /** * ProcessNativeMouseWheelMessage() processes WM_MOUSEWHEEL and * WM_MOUSEHWHEEL. Additionally, processes WM_VSCROLL and WM_HSCROLL if they @@ -350,6 +390,70 @@ private: UserPrefs mUserPrefs; + class SynthesizingEvent { + public: + SynthesizingEvent() : + mWnd(NULL), mMessage(0), mWParam(0), mLParam(0), + mStatus(NOT_SYNTHESIZING) + { + } + + ~SynthesizingEvent() {} + + static bool IsSynthesizing(); + + nsresult Synthesize(const POINTS& aCursorPoint, HWND aWnd, + UINT aMessage, WPARAM aWParam, LPARAM aLParam, + const BYTE (&aKeyStates)[256]); + + void NativeMessageReceived(nsWindow* aWindow, UINT aMessage, + WPARAM aWParam, LPARAM aLParam); + + void NotifyNativeMessageHandlingFinished(); + void NotifyInternalMessageHandlingFinished(); + + const POINTS& GetCursorPoint() const { return mCursorPoint; } + + private: + POINTS mCursorPoint; + HWND mWnd; + UINT mMessage; + WPARAM mWParam; + LPARAM mLParam; + BYTE mKeyState[256]; + BYTE mOriginalKeyState[256]; + + enum Status { + NOT_SYNTHESIZING, + SENDING_MESSAGE, + NATIVE_MESSAGE_RECEIVED, + INTERNAL_MESSAGE_POSTED, + }; + Status mStatus; + +#ifdef PR_LOGGING + const char* GetStatusName() + { + switch (mStatus) { + case NOT_SYNTHESIZING: + return "NOT_SYNTHESIZING"; + case SENDING_MESSAGE: + return "SENDING_MESSAGE"; + case NATIVE_MESSAGE_RECEIVED: + return "NATIVE_MESSAGE_RECEIVED"; + case INTERNAL_MESSAGE_POSTED: + return "INTERNAL_MESSAGE_POSTED"; + default: + return "Unknown"; + } + } +#endif + + void Finish(); + }; // SynthesizingEvent + + SynthesizingEvent* mSynthesizingEvent; + public: class Device { diff --git a/widget/windows/nsAppShell.cpp b/widget/windows/nsAppShell.cpp index 2d3725b0cc0a..10f5d8583fc7 100644 --- a/widget/windows/nsAppShell.cpp +++ b/widget/windows/nsAppShell.cpp @@ -43,6 +43,8 @@ #include "nsToolkit.h" #include "nsThreadUtils.h" #include "WinTaskbar.h" +#include "WinMouseScrollHandler.h" +#include "nsWindowDefs.h" #include "nsString.h" #include "nsIMM32Handler.h" #include "mozilla/widget/AudioSession.h" @@ -79,6 +81,19 @@ using mozilla::crashreporter::LSPAnnotate; static bool PeekUIMessage(MSG* aMsg) { + // For avoiding deadlock between our process and plugin process by + // mouse wheel messages, we're handling actually when we receive one of + // following internal messages which is posted by native mouse wheel message + // handler. Any other events, especially native modifier key events, should + // not be handled between native message and posted internal message because + // it may make different modifier key state or mouse cursor position between + // them. + if (mozilla::widget::MouseScrollHandler::IsWaitingInternalMessage() && + ::PeekMessageW(aMsg, NULL, MOZ_WM_MOUSEWHEEL_FIRST, + MOZ_WM_MOUSEWHEEL_LAST, PM_REMOVE)) { + return true; + } + MSG keyMsg, imeMsg, mouseMsg, *pMsg = 0; bool haveKeyMsg, haveIMEMsg, haveMouseMsg; diff --git a/widget/windows/nsWindow.cpp b/widget/windows/nsWindow.cpp index e499c5bcdbd1..8125db544aa0 100644 --- a/widget/windows/nsWindow.cpp +++ b/widget/windows/nsWindow.cpp @@ -5798,6 +5798,22 @@ nsWindow::SynthesizeNativeMouseEvent(nsIntPoint aPoint, return NS_OK; } +nsresult +nsWindow::SynthesizeNativeMouseScrollEvent(nsIntPoint aPoint, + PRUint32 aNativeMessage, + double aDeltaX, + double aDeltaY, + double aDeltaZ, + PRUint32 aModifierFlags, + PRUint32 aAdditionalFlags) +{ + return MouseScrollHandler::SynthesizeNativeMouseScrollEvent( + this, aPoint, aNativeMessage, + (aNativeMessage == WM_MOUSEWHEEL || aNativeMessage == WM_VSCROLL) ? + static_cast(aDeltaY) : static_cast(aDeltaX), + aModifierFlags, aAdditionalFlags); +} + /************************************************************** * * SECTION: OnXXX message handlers diff --git a/widget/windows/nsWindow.h b/widget/windows/nsWindow.h index d7690d23e7c7..aab98bfc5ccb 100644 --- a/widget/windows/nsWindow.h +++ b/widget/windows/nsWindow.h @@ -177,6 +177,13 @@ public: virtual nsresult SynthesizeNativeMouseEvent(nsIntPoint aPoint, PRUint32 aNativeMessage, PRUint32 aModifierFlags); + virtual nsresult SynthesizeNativeMouseScrollEvent(nsIntPoint aPoint, + PRUint32 aNativeMessage, + double aDeltaX, + double aDeltaY, + double aDeltaZ, + PRUint32 aModifierFlags, + PRUint32 aAdditionalFlags); NS_IMETHOD ResetInputState(); NS_IMETHOD_(void) SetInputContext(const InputContext& aContext, const InputContextAction& aAction); @@ -295,6 +302,8 @@ public: void PickerClosed(); bool const DestroyCalled() { return mDestroyCalled; } + + static void SetupKeyModifiersSequence(nsTArray* aArray, PRUint32 aModifiers); protected: // A magic number to identify the FAKETRACKPOINTSCROLLABLE window created @@ -458,7 +467,6 @@ protected: UINT MapFromNativeToDOM(UINT aNativeKeyCode); void StopFlashing(); static bool IsTopLevelMouseExit(HWND aWnd); - static void SetupKeyModifiersSequence(nsTArray* aArray, PRUint32 aModifiers); nsresult SetWindowClipRegion(const nsTArray& aRects, bool aIntersectWithExisting); nsIntRegion GetRegionToPaint(bool aForceFullRepaint, diff --git a/widget/windows/nsWindowDefs.h b/widget/windows/nsWindowDefs.h index ad9d86448627..931c46689d14 100644 --- a/widget/windows/nsWindowDefs.h +++ b/widget/windows/nsWindowDefs.h @@ -64,6 +64,9 @@ #define MOZ_WM_MOUSEHWHEEL (WM_APP+0x0311) #define MOZ_WM_VSCROLL (WM_APP+0x0312) #define MOZ_WM_HSCROLL (WM_APP+0x0313) +#define MOZ_WM_MOUSEWHEEL_FIRST MOZ_WM_MOUSEVWHEEL +#define MOZ_WM_MOUSEWHEEL_LAST MOZ_WM_HSCROLL + // Internal message for ensuring the file picker is visible on multi monitor // systems, and when the screen resolution changes. #define MOZ_WM_ENSUREVISIBLE (WM_APP + 14159)