mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-30 00:01:50 +00:00
Bug 672175 part.16 Implement nsIWidget::SynthesizeNativeMouseScrollEvent() on Windows r=jimm
This commit is contained in:
parent
c670feb072
commit
a60c46de7f
@ -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
|
||||
*
|
||||
|
@ -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<LPARAM>(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<KeyPair,10> 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<SHORT>(pt.x);
|
||||
pts.y = static_cast<SHORT>(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
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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<PRInt32>(aDeltaY) : static_cast<PRInt32>(aDeltaX),
|
||||
aModifierFlags, aAdditionalFlags);
|
||||
}
|
||||
|
||||
/**************************************************************
|
||||
*
|
||||
* SECTION: OnXXX message handlers
|
||||
|
@ -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<KeyPair>* 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<KeyPair>* aArray, PRUint32 aModifiers);
|
||||
nsresult SetWindowClipRegion(const nsTArray<nsIntRect>& aRects,
|
||||
bool aIntersectWithExisting);
|
||||
nsIntRegion GetRegionToPaint(bool aForceFullRepaint,
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user