Bug 605648 Support high resolution scrolling on Windows r=jimm+smaug

This commit is contained in:
Masayuki Nakano 2011-05-17 09:23:23 +09:00
parent 1d29d45277
commit 04f1d9f037
7 changed files with 385 additions and 132 deletions

View File

@ -1394,6 +1394,12 @@ nsEventStateManager::PreHandleEvent(nsPresContext* aPresContext,
handler.OnQueryDOMWidgetHittest(static_cast<nsQueryContentEvent*>(aEvent));
}
break;
case NS_QUERY_SCROLL_TARGET_INFO:
{
DoQueryScrollTargetInfo(static_cast<nsQueryContentEvent*>(aEvent),
aTargetFrame);
break;
}
case NS_SELECTION_SET:
{
nsSelectionEvent *selectionEvent =
@ -2564,7 +2570,8 @@ nsresult
nsEventStateManager::DoScrollText(nsIFrame* aTargetFrame,
nsMouseScrollEvent* aMouseEvent,
nsIScrollableFrame::ScrollUnit aScrollQuantity,
PRBool aAllowScrollSpeedOverride)
PRBool aAllowScrollSpeedOverride,
nsQueryContentEvent* aQueryEvent)
{
nsIScrollableFrame* frameToScroll = nsnull;
nsIFrame* scrollFrame = aTargetFrame;
@ -2643,6 +2650,19 @@ nsEventStateManager::DoScrollText(nsIFrame* aTargetFrame,
}
if (!passToParent && frameToScroll) {
if (aQueryEvent) {
nscoord appUnitsPerDevPixel =
aTargetFrame->PresContext()->AppUnitsPerDevPixel();
aQueryEvent->mReply.mLineHeight =
frameToScroll->GetLineScrollAmount().height / appUnitsPerDevPixel;
aQueryEvent->mReply.mPageHeight =
frameToScroll->GetPageScrollAmount().height / appUnitsPerDevPixel;
aQueryEvent->mReply.mPageWidth =
frameToScroll->GetPageScrollAmount().width / appUnitsPerDevPixel;
aQueryEvent->mSucceeded = PR_TRUE;
return NS_OK;
}
if (aScrollQuantity == nsIScrollableFrame::LINES) {
numLines =
nsMouseWheelTransaction::AccelerateWheelDelta(numLines, isHorizontal,
@ -2670,7 +2690,9 @@ nsEventStateManager::DoScrollText(nsIFrame* aTargetFrame,
nsIScrollableFrame::ScrollMode mode;
if (aMouseEvent->scrollFlags & nsMouseScrollEvent::kNoDefer) {
mode = nsIScrollableFrame::INSTANT;
} else if (aScrollQuantity != nsIScrollableFrame::DEVICE_PIXELS) {
} else if (aScrollQuantity != nsIScrollableFrame::DEVICE_PIXELS ||
(aMouseEvent->scrollFlags &
nsMouseScrollEvent::kAllowSmoothScroll) != 0) {
mode = nsIScrollableFrame::SMOOTH;
} else {
mode = nsIScrollableFrame::NORMAL;
@ -2688,7 +2710,7 @@ nsEventStateManager::DoScrollText(nsIFrame* aTargetFrame,
aTargetFrame->PresContext()->FrameManager()->GetRootFrame());
if (newFrame)
return DoScrollText(newFrame, aMouseEvent, aScrollQuantity,
aAllowScrollSpeedOverride);
aAllowScrollSpeedOverride, aQueryEvent);
}
aMouseEvent->scrollOverflow = numLines;
@ -3051,7 +3073,7 @@ nsEventStateManager::PostHandleEvent(nsPresContext* aPresContext,
}
if (aEvent->message == NS_MOUSE_PIXEL_SCROLL) {
if (action == MOUSE_SCROLL_N_LINES ||
if (action == MOUSE_SCROLL_N_LINES || action == MOUSE_SCROLL_PAGE ||
(msEvent->scrollFlags & nsMouseScrollEvent::kIsMomentum)) {
action = MOUSE_SCROLL_PIXELS;
} else {
@ -3059,7 +3081,7 @@ nsEventStateManager::PostHandleEvent(nsPresContext* aPresContext,
action = -1;
}
} else if (msEvent->scrollFlags & nsMouseScrollEvent::kHasPixels) {
if (action == MOUSE_SCROLL_N_LINES ||
if (useSysNumLines || action == MOUSE_SCROLL_N_LINES ||
(msEvent->scrollFlags & nsMouseScrollEvent::kIsMomentum)) {
// Don't scroll lines when a pixel scroll event will follow.
// Also, don't do history scrolling or zooming for momentum scrolls.
@ -4646,6 +4668,20 @@ nsEventStateManager::DoContentCommandScrollEvent(nsContentCommandEvent* aEvent)
return NS_OK;
}
void
nsEventStateManager::DoQueryScrollTargetInfo(nsQueryContentEvent* aEvent,
nsIFrame* aTargetFrame)
{
nsMouseScrollEvent* msEvent = aEvent->mInput.mMouseScrollEvent;
nsIScrollableFrame::ScrollUnit unit;
if (msEvent->scrollFlags & nsMouseScrollEvent::kIsFullPage) {
unit = nsIScrollableFrame::PAGES;
} else {
unit = nsIScrollableFrame::LINES;
}
DoScrollText(aTargetFrame, msEvent, unit, PR_FALSE, aEvent);
}
void
nsEventStateManager::SetActiveManager(nsEventStateManager* aNewESM,
nsIContent* aContent)

View File

@ -324,10 +324,19 @@ protected:
nsMouseScrollEvent* aEvent,
nsPresContext* aPresContext,
nsEventStatus* aStatus);
/**
* @param aQueryEvent If you set vailid pointer for this, DoScrollText()
* computes the line-height and page size of current
* mouse wheel scroll target and sets it to the event.
* And then, this method does NOT scroll any scrollable
* elements. I.e., you can just query the scroll target
* information.
*/
nsresult DoScrollText(nsIFrame* aTargetFrame,
nsMouseScrollEvent* aMouseEvent,
nsIScrollableFrame::ScrollUnit aScrollQuantity,
PRBool aAllowScrollSpeedOverride);
PRBool aAllowScrollSpeedOverride,
nsQueryContentEvent* aQueryEvent = nsnull);
void DoScrollHistory(PRInt32 direction);
void DoScrollZoom(nsIFrame *aTargetFrame, PRInt32 adjustment);
nsresult GetMarkupDocumentViewer(nsIMarkupDocumentViewer** aMv);
@ -397,6 +406,9 @@ protected:
nsresult DoContentCommandEvent(nsContentCommandEvent* aEvent);
nsresult DoContentCommandScrollEvent(nsContentCommandEvent* aEvent);
void DoQueryScrollTargetInfo(nsQueryContentEvent* aEvent,
nsIFrame* aTargetFrame);
PRBool RemoteQueryContentEvent(nsEvent *aEvent);
mozilla::dom::TabParent *GetCrossProcessTarget();
PRBool IsTargetCrossProcess(nsGUIEvent *aEvent);

View File

@ -415,6 +415,12 @@ class nsHashKey;
// Query if the DOM element under nsEvent::refPoint belongs to our widget
// or not.
#define NS_QUERY_DOM_WIDGET_HITTEST (NS_QUERY_CONTENT_EVENT_START + 9)
// Query for some information about mouse wheel event's target
// XXX This is used only for supporting high resolution mouse scroll on Windows
// and it's going to be reimplemented with another approach. At that time,
// this even is going to be removed. Therefore, DON'T use this event for
// other purpose.
#define NS_QUERY_SCROLL_TARGET_INFO (NS_QUERY_CONTENT_EVENT_START + 99)
// Video events
#ifdef MOZ_MEDIA
@ -1188,9 +1194,11 @@ public:
// as needed.
kNoDefer = 1 << 5, // For scrollable views, indicates scroll should not
// occur asynchronously.
kIsMomentum = 1 << 6 // Marks scroll events that aren't controlled by the
kIsMomentum = 1 << 6, // Marks scroll events that aren't controlled by the
// user but fire automatically as the result of a
// "momentum" scroll.
kAllowSmoothScroll = 1 << 7 // Allow smooth scroll for the pixel scroll
// event.
};
nsMouseScrollEvent(PRBool isTrusted, PRUint32 msg, nsIWidget *w)
@ -1285,6 +1293,13 @@ public:
refPoint = aPoint;
}
void InitForQueryScrollTargetInfo(nsMouseScrollEvent* aEvent)
{
NS_ASSERTION(message == NS_QUERY_SCROLL_TARGET_INFO,
"wrong initializer is called");
mInput.mMouseScrollEvent = aEvent;
}
PRUint32 GetSelectionStart(void) const
{
NS_ASSERTION(message == NS_QUERY_SELECTED_TEXT,
@ -1304,6 +1319,8 @@ public:
struct {
PRUint32 mOffset;
PRUint32 mLength;
// used by NS_QUERY_SCROLL_TARGET_INFO
nsMouseScrollEvent* mMouseScrollEvent;
} mInput;
struct {
void* mContentsRoot;
@ -1317,6 +1334,10 @@ public:
PRPackedBool mWidgetIsHit; // true if DOM element under mouse belongs to widget
// used by NS_QUERY_SELECTION_AS_TRANSFERABLE
nsCOMPtr<nsITransferable> mTransferable;
// used by NS_QUERY_SCROLL_TARGET_INFO
PRInt32 mLineHeight;
PRInt32 mPageWidth;
PRInt32 mPageHeight;
} mReply;
enum {
@ -1620,15 +1641,7 @@ enum nsDragDropEventStatus {
((evnt)->message == NS_PLUGIN_FOCUS))
#define NS_IS_QUERY_CONTENT_EVENT(evnt) \
(((evnt)->message == NS_QUERY_SELECTED_TEXT) || \
((evnt)->message == NS_QUERY_TEXT_CONTENT) || \
((evnt)->message == NS_QUERY_CARET_RECT) || \
((evnt)->message == NS_QUERY_TEXT_RECT) || \
((evnt)->message == NS_QUERY_EDITOR_RECT) || \
((evnt)->message == NS_QUERY_CONTENT_STATE) || \
((evnt)->message == NS_QUERY_SELECTION_AS_TRANSFERABLE) || \
((evnt)->message == NS_QUERY_CHARACTER_AT_POINT) || \
((evnt)->message == NS_QUERY_DOM_WIDGET_HITTEST))
((evnt)->eventStructType == NS_QUERY_CONTENT_EVENT)
#define NS_IS_SELECTION_EVENT(evnt) \
(((evnt)->message == NS_SELECTION_SET))
@ -1670,7 +1683,8 @@ enum nsDragDropEventStatus {
// cases, you should use NS_IS_IME_RELATED_EVENT instead.
#define NS_IS_IME_RELATED_EVENT(evnt) \
(NS_IS_IME_EVENT(evnt) || \
NS_IS_QUERY_CONTENT_EVENT(evnt) || \
(NS_IS_QUERY_CONTENT_EVENT(evnt) && \
evnt->message != NS_QUERY_SCROLL_TARGET_INFO) || \
NS_IS_SELECTION_EVENT(evnt))
/*

View File

@ -109,6 +109,50 @@ struct ParamTraits<nsInputEvent>
}
};
template<>
struct ParamTraits<nsMouseEvent_base>
{
typedef nsMouseEvent_base paramType;
static void Write(Message* aMsg, const paramType& aParam)
{
WriteParam(aMsg, static_cast<nsInputEvent>(aParam));
WriteParam(aMsg, aParam.button);
WriteParam(aMsg, aParam.pressure);
WriteParam(aMsg, aParam.inputSource);
}
static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
{
return ReadParam(aMsg, aIter, static_cast<nsInputEvent*>(aResult)) &&
ReadParam(aMsg, aIter, &aResult->button) &&
ReadParam(aMsg, aIter, &aResult->pressure) &&
ReadParam(aMsg, aIter, &aResult->inputSource);
}
};
template<>
struct ParamTraits<nsMouseScrollEvent>
{
typedef nsMouseScrollEvent paramType;
static void Write(Message* aMsg, const paramType& aParam)
{
WriteParam(aMsg, static_cast<nsMouseEvent_base>(aParam));
WriteParam(aMsg, aParam.scrollFlags);
WriteParam(aMsg, aParam.delta);
WriteParam(aMsg, aParam.scrollOverflow);
}
static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
{
return ReadParam(aMsg, aIter, static_cast<nsMouseEvent_base*>(aResult)) &&
ReadParam(aMsg, aIter, &aResult->scrollFlags) &&
ReadParam(aMsg, aIter, &aResult->delta) &&
ReadParam(aMsg, aIter, &aResult->scrollOverflow);
}
};
template<>
struct ParamTraits<nsTextRangeStyle>
{
@ -235,12 +279,16 @@ struct ParamTraits<nsQueryContentEvent>
WriteParam(aMsg, aParam.mSucceeded);
WriteParam(aMsg, aParam.mInput.mOffset);
WriteParam(aMsg, aParam.mInput.mLength);
WriteParam(aMsg, *aParam.mInput.mMouseScrollEvent);
WriteParam(aMsg, aParam.mReply.mOffset);
WriteParam(aMsg, aParam.mReply.mString);
WriteParam(aMsg, aParam.mReply.mRect);
WriteParam(aMsg, aParam.mReply.mReversed);
WriteParam(aMsg, aParam.mReply.mHasSelection);
WriteParam(aMsg, aParam.mReply.mWidgetIsHit);
WriteParam(aMsg, aParam.mReply.mLineHeight);
WriteParam(aMsg, aParam.mReply.mPageHeight);
WriteParam(aMsg, aParam.mReply.mPageWidth);
}
static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
@ -250,12 +298,16 @@ struct ParamTraits<nsQueryContentEvent>
ReadParam(aMsg, aIter, &aResult->mSucceeded) &&
ReadParam(aMsg, aIter, &aResult->mInput.mOffset) &&
ReadParam(aMsg, aIter, &aResult->mInput.mLength) &&
ReadParam(aMsg, aIter, aResult->mInput.mMouseScrollEvent) &&
ReadParam(aMsg, aIter, &aResult->mReply.mOffset) &&
ReadParam(aMsg, aIter, &aResult->mReply.mString) &&
ReadParam(aMsg, aIter, &aResult->mReply.mRect) &&
ReadParam(aMsg, aIter, &aResult->mReply.mReversed) &&
ReadParam(aMsg, aIter, &aResult->mReply.mHasSelection) &&
ReadParam(aMsg, aIter, &aResult->mReply.mWidgetIsHit);
ReadParam(aMsg, aIter, &aResult->mReply.mWidgetIsHit) &&
ReadParam(aMsg, aIter, &aResult->mReply.mLineHeight) &&
ReadParam(aMsg, aIter, &aResult->mReply.mPageHeight) &&
ReadParam(aMsg, aIter, &aResult->mReply.mPageWidth);
}
};

View File

@ -298,6 +298,18 @@ PRUint32 nsWindow::sOOPPPluginFocusEvent =
MSG nsWindow::sRedirectedKeyDown;
PRBool nsWindow::sNeedsToInitMouseWheelSettings = PR_TRUE;
ULONG nsWindow::sMouseWheelScrollLines = 0;
ULONG nsWindow::sMouseWheelScrollChars = 0;
HWND nsWindow::sLastMouseWheelWnd = NULL;
PRInt32 nsWindow::sRemainingDeltaForScroll = 0;
PRInt32 nsWindow::sRemainingDeltaForPixel = 0;
PRBool nsWindow::sLastMouseWheelDeltaIsPositive = PR_FALSE;
PRBool nsWindow::sLastMouseWheelOrientationIsVertical = PR_FALSE;
PRBool nsWindow::sLastMouseWheelUnitIsPage = PR_FALSE;
PRUint32 nsWindow::sLastMouseWheelTime = 0;
/**************************************************************
*
* SECTION: globals variables
@ -4524,8 +4536,6 @@ PRBool nsWindow::ProcessMessage(UINT msg, WPARAM &wParam, LPARAM &lParam,
PRBool result = PR_FALSE; // call the default nsWindow proc
*aRetValue = 0;
static PRBool getWheelInfo = PR_TRUE;
#if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
// Glass hit testing w/custom transparent margins
LRESULT dwmHitResult;
@ -5187,7 +5197,12 @@ PRBool nsWindow::ProcessMessage(UINT msg, WPARAM &wParam, LPARAM &lParam,
break;
case WM_SETTINGCHANGE:
getWheelInfo = PR_TRUE;
switch (wParam) {
case SPI_SETWHEELSCROLLLINES:
case SPI_SETWHEELSCROLLCHARS:
sNeedsToInitMouseWheelSettings = PR_TRUE;
break;
}
break;
case WM_INPUTLANGCHANGEREQUEST:
@ -5259,8 +5274,9 @@ PRBool nsWindow::ProcessMessage(UINT msg, WPARAM &wParam, LPARAM &lParam,
// If OnMouseWheel returns false, OnMouseWheel processed the event internally.
// 'result' and 'aRetValue' will be set based on what we did with the event, so
// we should fall through.
if (OnMouseWheel(msg, wParam, lParam, getWheelInfo, result, aRetValue))
if (OnMouseWheel(msg, wParam, lParam, result, aRetValue)) {
return result;
}
}
break;
@ -6281,118 +6297,152 @@ PRUint16 nsWindow::GetMouseInputSource()
return inputSource;
}
/* static */ void
nsWindow::InitMouseWheelScrollData()
{
if (!sNeedsToInitMouseWheelSettings) {
return;
}
sNeedsToInitMouseWheelSettings = PR_FALSE;
ResetRemainingWheelDelta();
if (!::SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0,
&sMouseWheelScrollLines, 0)) {
NS_WARNING("Failed to get SPI_GETWHEELSCROLLLINES");
sMouseWheelScrollLines = 3;
} else if (sMouseWheelScrollLines > WHEEL_DELTA) {
// sMouseWheelScrollLines usually equals 3 or 0 (for no scrolling)
// However, if sMouseWheelScrollLines > WHEEL_DELTA, we assume that
// the mouse driver wants a page scroll. The docs state that
// sMouseWheelScrollLines should explicitly equal WHEEL_PAGESCROLL, but
// since some mouse drivers use an arbitrary large number instead,
// we have to handle that as well.
sMouseWheelScrollLines = WHEEL_PAGESCROLL;
}
if (!::SystemParametersInfo(SPI_GETWHEELSCROLLCHARS, 0,
&sMouseWheelScrollChars, 0)) {
NS_ASSERTION(!nsUXThemeData::sIsVistaOrLater,
"Failed to get SPI_GETWHEELSCROLLCHARS");
sMouseWheelScrollChars = 1;
} else if (sMouseWheelScrollChars > WHEEL_DELTA) {
// See the comments for the case sMouseWheelScrollLines > WHEEL_DELTA.
sMouseWheelScrollChars = WHEEL_PAGESCROLL;
}
}
/* static */
void
nsWindow::ResetRemainingWheelDelta()
{
sRemainingDeltaForPixel = 0;
sRemainingDeltaForScroll = 0;
sLastMouseWheelWnd = NULL;
}
static PRInt32 RoundDelta(double aDelta)
{
return aDelta >= 0 ? (PRInt32)NS_floor(aDelta) : (PRInt32)NS_ceil(aDelta);
}
/*
* OnMouseWheel - mouse wheel event processing. This was originally embedded
* within the message case block. If returning true result should be returned
* immediately (no more processing).
*/
PRBool nsWindow::OnMouseWheel(UINT msg, WPARAM wParam, LPARAM lParam, PRBool& getWheelInfo, PRBool& result, LRESULT *aRetValue)
PRBool
nsWindow::OnMouseWheel(UINT aMessage, WPARAM aWParam, LPARAM aLParam,
PRBool& aHandled, LRESULT *aRetValue)
{
// Handle both flavors of mouse wheel events.
static int iDeltaPerLine, iDeltaPerChar;
static ULONG ulScrollLines, ulScrollChars = 1;
static int currentVDelta, currentHDelta;
static HWND currentWindow = 0;
InitMouseWheelScrollData();
PRBool isVertical = msg == WM_MOUSEWHEEL;
// Get mouse wheel metrics (but only once).
if (getWheelInfo) {
getWheelInfo = PR_FALSE;
SystemParametersInfo (SPI_GETWHEELSCROLLLINES, 0, &ulScrollLines, 0);
// ulScrollLines usually equals 3 or 0 (for no scrolling)
// WHEEL_DELTA equals 120, so iDeltaPerLine will be 40.
// However, if ulScrollLines > WHEEL_DELTA, we assume that
// the mouse driver wants a page scroll. The docs state that
// ulScrollLines should explicitly equal WHEEL_PAGESCROLL, but
// since some mouse drivers use an arbitrary large number instead,
// we have to handle that as well.
iDeltaPerLine = 0;
if (ulScrollLines) {
if (ulScrollLines <= WHEEL_DELTA) {
iDeltaPerLine = WHEEL_DELTA / ulScrollLines;
} else {
ulScrollLines = WHEEL_PAGESCROLL;
}
}
if (!SystemParametersInfo(SPI_GETWHEELSCROLLCHARS, 0,
&ulScrollChars, 0)) {
// Note that we may always fail to get the value before Win Vista.
ulScrollChars = 1;
}
iDeltaPerChar = 0;
if (ulScrollChars) {
if (ulScrollChars <= WHEEL_DELTA) {
iDeltaPerChar = WHEEL_DELTA / ulScrollChars;
} else {
ulScrollChars = WHEEL_PAGESCROLL;
}
}
PRBool isVertical = (aMessage == WM_MOUSEWHEEL);
if ((isVertical && sMouseWheelScrollLines == 0) ||
(!isVertical && sMouseWheelScrollChars == 0)) {
// XXX I think that we should dispatch mouse wheel events even if the
// operation will not scroll because the wheel operation really happened
// and web application may want to handle the event for non-scroll action.
ResetRemainingWheelDelta();
*aRetValue = isVertical ? TRUE : FALSE; // means we don't process it
aHandled = PR_FALSE;
return PR_FALSE;
}
if ((isVertical && ulScrollLines != WHEEL_PAGESCROLL && !iDeltaPerLine) ||
(!isVertical && ulScrollChars != WHEEL_PAGESCROLL && !iDeltaPerChar))
return PR_FALSE; // break
// The mousewheel event will be dispatched to the toplevel
// window. We need to give it to the child window.
PRBool quit;
if (!HandleScrollingPlugins(msg, wParam, lParam, result, aRetValue, quit))
if (!HandleScrollingPlugins(aMessage, aWParam, aLParam,
aHandled, aRetValue, quit)) {
ResetRemainingWheelDelta();
return quit; // return immediately if it's not our window
}
// We should cancel the surplus delta if the current window is not
// same as previous.
if (currentWindow != mWnd) {
currentVDelta = 0;
currentHDelta = 0;
currentWindow = mWnd;
}
nsMouseScrollEvent scrollEvent(PR_TRUE, NS_MOUSE_SCROLL, this);
scrollEvent.delta = 0;
if (isVertical) {
scrollEvent.scrollFlags = nsMouseScrollEvent::kIsVertical;
if (ulScrollLines == WHEEL_PAGESCROLL) {
scrollEvent.scrollFlags |= nsMouseScrollEvent::kIsFullPage;
scrollEvent.delta = (((short) HIWORD (wParam)) > 0) ? -1 : 1;
} else {
currentVDelta -= (short) HIWORD (wParam);
if (PR_ABS(currentVDelta) >= iDeltaPerLine) {
scrollEvent.delta = currentVDelta / iDeltaPerLine;
currentVDelta %= iDeltaPerLine;
}
}
} else {
scrollEvent.scrollFlags = nsMouseScrollEvent::kIsHorizontal;
if (ulScrollChars == WHEEL_PAGESCROLL) {
scrollEvent.scrollFlags |= nsMouseScrollEvent::kIsFullPage;
scrollEvent.delta = (((short) HIWORD (wParam)) > 0) ? 1 : -1;
} else {
currentHDelta += (short) HIWORD (wParam);
if (PR_ABS(currentHDelta) >= iDeltaPerChar) {
scrollEvent.delta = currentHDelta / iDeltaPerChar;
currentHDelta %= iDeltaPerChar;
}
}
}
if (!scrollEvent.delta) {
// We store the wheel delta, and it will be used next wheel message, so,
// we consume this message actually. We shouldn't call next wndproc.
result = PR_TRUE;
return PR_FALSE; // break
PRInt32 nativeDelta = (short)HIWORD(aWParam);
if (!nativeDelta) {
*aRetValue = isVertical ? TRUE : FALSE; // means we don't process it
aHandled = PR_FALSE;
ResetRemainingWheelDelta();
return PR_FALSE; // We cannot process this message
}
// 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);
PRBool isPageScroll =
((isVertical && sMouseWheelScrollLines == WHEEL_PAGESCROLL) ||
(!isVertical && sMouseWheelScrollChars == WHEEL_PAGESCROLL));
// Discard the remaining delta if current wheel message and last one are
// received by different window or to scroll different direction or
// different unit scroll. Furthermore, if the last event was too old.
PRUint32 now = PR_IntervalToMilliseconds(PR_IntervalNow());
if (sLastMouseWheelWnd &&
(sLastMouseWheelWnd != mWnd ||
sLastMouseWheelDeltaIsPositive != (nativeDelta > 0) ||
sLastMouseWheelOrientationIsVertical != isVertical ||
sLastMouseWheelUnitIsPage != isPageScroll ||
now - sLastMouseWheelTime > 1500)) {
ResetRemainingWheelDelta();
}
sLastMouseWheelWnd = mWnd;
sLastMouseWheelDeltaIsPositive = (nativeDelta > 0);
sLastMouseWheelOrientationIsVertical = isVertical;
sLastMouseWheelUnitIsPage = isPageScroll;
sLastMouseWheelTime = now;
nsMouseScrollEvent testEvent(PR_TRUE, NS_MOUSE_SCROLL, this);
InitEvent(testEvent);
testEvent.scrollFlags = isPageScroll ? nsMouseScrollEvent::kIsFullPage : 0;
testEvent.scrollFlags |= isVertical ? nsMouseScrollEvent::kIsVertical :
nsMouseScrollEvent::kIsHorizontal;
testEvent.delta = sLastMouseWheelDeltaIsPositive ? -1 : 1;
nsQueryContentEvent queryEvent(PR_TRUE, NS_QUERY_SCROLL_TARGET_INFO, this);
InitEvent(queryEvent);
queryEvent.InitForQueryScrollTargetInfo(&testEvent);
DispatchWindowEvent(&queryEvent);
// If the necessary interger isn't larger than 0, we should assume that
// the event failed for us.
if (queryEvent.mSucceeded) {
if (isPageScroll) {
if (isVertical) {
queryEvent.mSucceeded = (queryEvent.mReply.mPageHeight > 0);
} else {
queryEvent.mSucceeded = (queryEvent.mReply.mPageWidth > 0);
}
} else {
queryEvent.mSucceeded = (queryEvent.mReply.mLineHeight > 0);
}
}
*aRetValue = isVertical ? FALSE : TRUE; // means we process this message
nsModifierKeyState modKeyState;
// Our positive delta value means to bottom or right.
// But positive nativeDelta value means to top or right.
// Use orienter for computing our delta value.
PRInt32 orienter = isVertical ? -1 : 1;
// 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.)
@ -6401,25 +6451,97 @@ PRBool nsWindow::OnMouseWheel(UINT msg, WPARAM wParam, LPARAM lParam, PRBool& ge
static_cast<DWORD>(::GetMessageTime()) < mAssumeWheelIsZoomUntil) {
isControl = PR_TRUE;
} else {
isControl = IS_VK_DOWN(NS_VK_CONTROL);
isControl = modKeyState.mIsControlDown;
}
scrollEvent.isShift = IS_VK_DOWN(NS_VK_SHIFT);
scrollEvent.isControl = isControl;
scrollEvent.isMeta = PR_FALSE;
scrollEvent.isAlt = IS_VK_DOWN(NS_VK_ALT);
nsMouseScrollEvent scrollEvent(PR_TRUE, NS_MOUSE_SCROLL, this);
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.
// If the query event failed, we cannot send pixel events.
scrollEvent.scrollFlags =
queryEvent.mSucceeded ? nsMouseScrollEvent::kHasPixels : 0;
scrollEvent.isShift = modKeyState.mIsShiftDown;
scrollEvent.isControl = isControl;
scrollEvent.isMeta = PR_FALSE;
scrollEvent.isAlt = modKeyState.mIsAltDown;
if (result)
*aRetValue = isVertical ? 0 : TRUE;
return PR_FALSE; // break;
}
PRInt32 nativeDeltaForScroll = nativeDelta + sRemainingDeltaForScroll;
if (isPageScroll) {
scrollEvent.scrollFlags |= nsMouseScrollEvent::kIsFullPage;
if (isVertical) {
scrollEvent.scrollFlags |= nsMouseScrollEvent::kIsVertical;
} else {
scrollEvent.scrollFlags |= nsMouseScrollEvent::kIsHorizontal;
}
scrollEvent.delta = nativeDeltaForScroll * orienter / WHEEL_DELTA;
PRInt32 recomputedNativeDelta = scrollEvent.delta * orienter / WHEEL_DELTA;
sRemainingDeltaForScroll = nativeDeltaForScroll - recomputedNativeDelta;
} else {
double deltaPerUnit;
if (isVertical) {
scrollEvent.scrollFlags |= nsMouseScrollEvent::kIsVertical;
deltaPerUnit = (double)WHEEL_DELTA / sMouseWheelScrollLines;
} else {
scrollEvent.scrollFlags |= nsMouseScrollEvent::kIsHorizontal;
deltaPerUnit = (double)WHEEL_DELTA / sMouseWheelScrollChars;
}
scrollEvent.delta =
RoundDelta((double)nativeDeltaForScroll * orienter / deltaPerUnit);
PRInt32 recomputedNativeDelta =
(PRInt32)(scrollEvent.delta * orienter * deltaPerUnit);
sRemainingDeltaForScroll = nativeDeltaForScroll - recomputedNativeDelta;
}
if (scrollEvent.delta) {
aHandled = DispatchWindowEvent(&scrollEvent);
if (mOnDestroyCalled) {
ResetRemainingWheelDelta();
return PR_FALSE;
}
}
// If the query event failed, we cannot send pixel events.
if (!queryEvent.mSucceeded) {
sRemainingDeltaForPixel = 0;
return PR_FALSE;
}
nsMouseScrollEvent pixelEvent(PR_TRUE, NS_MOUSE_PIXEL_SCROLL, this);
InitEvent(pixelEvent);
pixelEvent.scrollFlags = nsMouseScrollEvent::kAllowSmoothScroll |
(scrollEvent.scrollFlags & ~nsMouseScrollEvent::kHasPixels);
pixelEvent.isShift = modKeyState.mIsShiftDown;
pixelEvent.isControl = modKeyState.mIsControlDown;
pixelEvent.isMeta = PR_FALSE;
pixelEvent.isAlt = modKeyState.mIsAltDown;
PRInt32 nativeDeltaForPixel = nativeDelta + sRemainingDeltaForPixel;
double deltaPerPixel;
if (isPageScroll) {
if (isVertical) {
deltaPerPixel = (double)WHEEL_DELTA / queryEvent.mReply.mPageHeight;
} else {
deltaPerPixel = (double)WHEEL_DELTA / queryEvent.mReply.mPageWidth;
}
} else {
if (isVertical) {
deltaPerPixel = (double)WHEEL_DELTA / sMouseWheelScrollLines;
} else {
deltaPerPixel = (double)WHEEL_DELTA / sMouseWheelScrollChars;
}
deltaPerPixel /= queryEvent.mReply.mLineHeight;
}
pixelEvent.delta =
RoundDelta((double)nativeDeltaForPixel * orienter / deltaPerPixel);
PRInt32 recomputedNativeDelta =
(PRInt32)(pixelEvent.delta * orienter * deltaPerPixel);
sRemainingDeltaForPixel = nativeDeltaForPixel - recomputedNativeDelta;
if (pixelEvent.delta != 0) {
aHandled = DispatchWindowEvent(&pixelEvent);
}
return PR_FALSE;
}
static PRBool
StringCaseInsensitiveEquals(const PRUnichar* aChars1, const PRUint32 aNumChars1,

View File

@ -411,8 +411,8 @@ protected:
BOOL OnInputLangChange(HKL aHKL);
PRBool OnPaint(HDC aDC, PRUint32 aNestingLevel);
void OnWindowPosChanged(WINDOWPOS *wp, PRBool& aResult);
PRBool OnMouseWheel(UINT msg, WPARAM wParam, LPARAM lParam,
PRBool& result, PRBool& getWheelInfo,
PRBool OnMouseWheel(UINT aMessage, WPARAM aWParam,
LPARAM aLParam, PRBool& aHandled,
LRESULT *aRetValue);
void OnWindowPosChanging(LPWINDOWPOS& info);
@ -616,6 +616,20 @@ protected:
// was reirected to SendInput() API by OnKeyDown().
static MSG sRedirectedKeyDown;
static PRBool sNeedsToInitMouseWheelSettings;
static ULONG sMouseWheelScrollLines;
static ULONG sMouseWheelScrollChars;
static void InitMouseWheelScrollData();
static HWND sLastMouseWheelWnd;
static PRInt32 sRemainingDeltaForScroll;
static PRInt32 sRemainingDeltaForPixel;
static PRBool sLastMouseWheelDeltaIsPositive;
static PRBool sLastMouseWheelOrientationIsVertical;
static PRBool sLastMouseWheelUnitIsPage;
static PRUint32 sLastMouseWheelTime; // in milliseconds
static void ResetRemainingWheelDelta();
// 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.
@ -649,7 +663,6 @@ protected:
nsRefPtr<nsWindow> mWindow;
const MSG &mMsg;
};
};
/**

View File

@ -90,6 +90,10 @@
#define SPI_GETWHEELSCROLLCHARS 0x006C
#endif
#ifndef SPI_SETWHEELSCROLLCHARS
#define SPI_SETWHEELSCROLLCHARS 0x006D
#endif
#ifndef MAPVK_VSC_TO_VK
#define MAPVK_VK_TO_VSC 0
#define MAPVK_VSC_TO_VK 1