Bug 462809 - Interpretation of scroll events on Windows and OS X, r=vladimir, ui-r=beltzner

This commit is contained in:
Margaret Leibovic 2009-08-04 14:28:17 -07:00
Родитель 067320254c
Коммит 65444db3df
3 изменённых файлов: 193 добавлений и 2 удалений

Просмотреть файл

@ -963,9 +963,16 @@ pref("mousewheel.transaction.ignoremovedelay", 100);
// Macbook touchpad two finger pixel scrolling
pref("mousewheel.enable_pixel_scrolling", true);
// prefs for improved windows scrolling model
// number of mousewheel clicks when acceleration starts
// acceleration can be turned off if pref is set to -1
pref("mousewheel.acceleration.start", 3);
// factor to be muliplied for constant acceleration
pref("mousewheel.acceleration.factor", 10);
// 0=lines, 1=pages, 2=history , 3=text size
pref("mousewheel.withnokey.action",0);
pref("mousewheel.withnokey.numlines",1);
pref("mousewheel.withnokey.numlines",6);
pref("mousewheel.withnokey.sysnumlines",true);
pref("mousewheel.withcontrolkey.action",0);
pref("mousewheel.withcontrolkey.numlines",1);

Просмотреть файл

@ -120,7 +120,9 @@
#include "nsIDOMNSUIEvent.h"
#include "nsITheme.h"
#include "nsIPrefBranch.h"
#include "nsIPrefBranch2.h"
#include "nsIPrefService.h"
#include "nsIObserver.h"
#include "nsIObserverService.h"
#include "nsIScreenManager.h"
#include "imgIContainer.h"
@ -190,6 +192,105 @@
#include "nsWindowDefs.h"
// For scroll wheel calculations
#include "nsITimer.h"
/**************************************************************
*
* nsScrollPrefObserver Class for scroll acceleration prefs
*
**************************************************************/
class nsScrollPrefObserver : public nsIObserver
{
public:
nsScrollPrefObserver();
int GetScrollAccelerationStart();
int GetScrollAccelerationFactor();
int GetScrollNumLines();
void RemoveObservers();
NS_DECL_ISUPPORTS
NS_DECL_NSIOBSERVER
private:
nsCOMPtr<nsIPrefBranch2> mPrefBranch;
int mScrollAccelerationStart;
int mScrollAccelerationFactor;
int mScrollNumLines;
};
NS_IMPL_ISUPPORTS1(nsScrollPrefObserver, nsScrollPrefObserver)
nsScrollPrefObserver::nsScrollPrefObserver()
{
nsresult rv;
mPrefBranch = do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
rv = mPrefBranch->GetIntPref("mousewheel.acceleration.start",
&mScrollAccelerationStart);
NS_ABORT_IF_FALSE(NS_SUCCEEDED(rv),
"Failed to get pref: mousewheel.acceleration.start");
rv = mPrefBranch->AddObserver("mousewheel.acceleration.start",
this, PR_FALSE);
NS_ABORT_IF_FALSE(NS_SUCCEEDED(rv),
"Failed to add pref observer: mousewheel.acceleration.start");
rv = mPrefBranch->GetIntPref("mousewheel.acceleration.factor",
&mScrollAccelerationFactor);
NS_ABORT_IF_FALSE(NS_SUCCEEDED(rv),
"Failed to get pref: mousewheel.acceleration.factor");
rv = mPrefBranch->AddObserver("mousewheel.acceleration.factor",
this, PR_FALSE);
NS_ABORT_IF_FALSE(NS_SUCCEEDED(rv),
"Failed to add pref observer: mousewheel.acceleration.factor");
rv = mPrefBranch->GetIntPref("mousewheel.withnokey.numlines",
&mScrollNumLines);
NS_ABORT_IF_FALSE(NS_SUCCEEDED(rv),
"Failed to get pref: mousewheel.withnokey.numlines");
rv = mPrefBranch->AddObserver("mousewheel.withnokey.numlines",
this, PR_FALSE);
NS_ABORT_IF_FALSE(NS_SUCCEEDED(rv),
"Failed to add pref observer: mousewheel.withnokey.numlines");
}
int nsScrollPrefObserver::GetScrollAccelerationStart()
{
return mScrollAccelerationStart;
}
int nsScrollPrefObserver::GetScrollAccelerationFactor()
{
return mScrollAccelerationFactor;
}
int nsScrollPrefObserver::GetScrollNumLines()
{
return mScrollNumLines;
}
void nsScrollPrefObserver::RemoveObservers()
{
mPrefBranch->RemoveObserver("mousewheel.acceleration.start", this);
mPrefBranch->RemoveObserver("mousewheel.acceleration.factor", this);
mPrefBranch->RemoveObserver("mousewheel.withnokey.numlines", this);
}
NS_IMETHODIMP nsScrollPrefObserver::Observe(nsISupports *aSubject,
const char *aTopic,
const PRUnichar *aData)
{
mPrefBranch->GetIntPref("mousewheel.acceleration.start",
&mScrollAccelerationStart);
mPrefBranch->GetIntPref("mousewheel.acceleration.factor",
&mScrollAccelerationFactor);
mPrefBranch->GetIntPref("mousewheel.withnokey.numlines",
&mScrollNumLines);
return NS_OK;
}
/**************************************************************
**************************************************************
**
@ -291,6 +392,9 @@ static PRBool gWindowsVisible = PR_FALSE;
static NS_DEFINE_CID(kCClipboardCID, NS_CLIPBOARD_CID);
// Global scroll pref observer for scroll acceleration prefs
static nsScrollPrefObserver* gScrollPrefObserver = nsnull;
/**************************************************************
**************************************************************
**
@ -351,6 +455,9 @@ nsWindow::nsWindow() : nsBaseWidget()
mBrush = ::CreateSolidBrush(NSRGB_2_COLOREF(mBackground));
mForeground = ::GetSysColor(COLOR_WINDOWTEXT);
// To be used for scroll acceleration
mScrollSeriesCounter = 0;
// Global initialization
if (!sInstanceCount) {
#if !defined(WINCE)
@ -360,6 +467,9 @@ nsWindow::nsWindow() : nsBaseWidget()
// Init IME handler
nsIMM32Handler::Initialize();
// Init scroll pref observer for scroll acceleration
NS_IF_ADDREF(gScrollPrefObserver = new nsScrollPrefObserver());
#ifdef NS_ENABLE_TSF
nsTextStore::Initialize();
#endif
@ -410,6 +520,9 @@ nsWindow::~nsWindow()
// delete any of the IME structures that we allocated
nsIMM32Handler::Terminate();
#endif // !defined(WINCE)
gScrollPrefObserver->RemoveObservers();
NS_RELEASE(gScrollPrefObserver);
}
#if !defined(WINCE)
@ -4823,6 +4936,10 @@ PRBool nsWindow::OnMouseWheel(UINT msg, WPARAM wParam, LPARAM lParam, PRBool& ge
currentWindow = mWnd;
}
// Keep track of whether or not the scroll notification is part of a series
// in order to calculate appropriate acceleration effect
UpdateMouseWheelSeriesCounter();
nsMouseScrollEvent scrollEvent(PR_TRUE, NS_MOUSE_SCROLL, this);
scrollEvent.delta = 0;
if (isVertical) {
@ -4833,7 +4950,10 @@ PRBool nsWindow::OnMouseWheel(UINT msg, WPARAM wParam, LPARAM lParam, PRBool& ge
} else {
currentVDelta -= (short) HIWORD (wParam);
if (PR_ABS(currentVDelta) >= iDeltaPerLine) {
scrollEvent.delta = currentVDelta / iDeltaPerLine;
// Compute delta to create acceleration effect
scrollEvent.delta = ComputeMouseWheelDelta(currentVDelta,
iDeltaPerLine,
ulScrollLines);
currentVDelta %= iDeltaPerLine;
}
}
@ -4870,6 +4990,64 @@ PRBool nsWindow::OnMouseWheel(UINT msg, WPARAM wParam, LPARAM lParam, PRBool& ge
return PR_FALSE; // break;
}
// Reset scrollSeriesCounter when timer finishes (scroll series has ended)
void nsWindow::OnMouseWheelTimeout(nsITimer* aTimer, void* aClosure)
{
nsWindow* window = (nsWindow*) aClosure;
window->mScrollSeriesCounter = 0;
}
// Increment scrollSeriesCount and reset timer to keep count going
void nsWindow::UpdateMouseWheelSeriesCounter()
{
mScrollSeriesCounter++;
int scrollSeriesTimeout = 80;
static nsITimer* scrollTimer;
if (!scrollTimer) {
nsCOMPtr<nsITimer> timer = do_CreateInstance(NS_TIMER_CONTRACTID);
if (!timer)
return;
timer.swap(scrollTimer);
}
scrollTimer->Cancel();
nsresult rv =
scrollTimer->InitWithFuncCallback(OnMouseWheelTimeout, this,
scrollSeriesTimeout,
nsITimer::TYPE_ONE_SHOT);
NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "nsITimer::InitWithFuncCallback failed");
}
// If the scroll notification is part of a series of notifications we should
// increase scollEvent.delta to create an acceleration effect
int nsWindow::ComputeMouseWheelDelta(int currentVDelta,
int iDeltaPerLine,
ULONG ulScrollLines)
{
// scrollAccelerationStart: click number at which acceleration starts
int scrollAccelerationStart = gScrollPrefObserver->GetScrollAccelerationStart();
// scrollNumlines: number of lines per scroll before acceleration
int scrollNumLines = gScrollPrefObserver->GetScrollNumLines();
// scrollAccelerationFactor: factor muliplied for constant acceleration
int scrollAccelerationFactor = gScrollPrefObserver->GetScrollAccelerationFactor();
// compute delta that obeys numlines pref
int ulScrollLinesInt = static_cast<int>(ulScrollLines);
// currentVDelta is a multiple of (iDeltaPerLine * ulScrollLinesInt)
int delta = scrollNumLines * currentVDelta / (iDeltaPerLine * ulScrollLinesInt);
// mScrollSeriesCounter: the index of the scroll notification in a series
if (mScrollSeriesCounter < scrollAccelerationStart ||
scrollAccelerationStart < 0 ||
scrollAccelerationFactor < 0)
return delta;
else
return int(0.5 + delta * mScrollSeriesCounter *
(double) scrollAccelerationFactor / 10);
}
#endif // !defined(WINCE_WINDOWS_MOBILE)
static PRBool

Просмотреть файл

@ -325,6 +325,11 @@ protected:
PRBool OnMouseWheel(UINT msg, WPARAM wParam, LPARAM lParam,
PRBool& result, PRBool& getWheelInfo,
LRESULT *aRetValue);
static void OnMouseWheelTimeout(nsITimer* aTimer, void* aClosure);
void UpdateMouseWheelSeriesCounter();
int ComputeMouseWheelDelta(int currentVDelta,
int iDeltaPerLine,
ULONG ulScrollLines);
#endif // !defined(WINCE_WINDOWS_MOBILE)
#if !defined(WINCE)
void OnWindowPosChanging(LPWINDOWPOS& info);
@ -430,6 +435,7 @@ protected:
nsNativeDragTarget* mNativeDragTarget;
HKL mLastKeyboardLayout;
nsPopupType mPopupType;
int mScrollSeriesCounter;
static PRUint32 sInstanceCount;
static TriStateBool sCanQuit;