From f43080340b31618cd5319d607a240073044e2084 Mon Sep 17 00:00:00 2001 From: Kirill Gavrilov Date: Thu, 31 Jan 2019 21:51:17 +0300 Subject: [PATCH] StWindow, Windows - fix enhanced scroll input --- StCore/StCocoaView.mm | 8 ++-- StCore/StWindowImpl.cpp | 4 ++ StCore/StWindowImpl.h | 1 + StCore/StWindowImplLin.cpp | 2 +- StCore/StWindowImplWin.cpp | 35 ++++++++++------- StGLWidgets/StGLImageRegion.cpp | 42 ++++++++++---------- StGLWidgets/StGLScrollArea.cpp | 14 ++++--- StOutPageFlip/StDXNVWindow.cpp | 25 ++++++------ include/StCore/StEvent.h | 59 ++++++++++++++++++++++++++++ include/StGLWidgets/StGLScrollArea.h | 1 + 10 files changed, 133 insertions(+), 58 deletions(-) diff --git a/StCore/StCocoaView.mm b/StCore/StCocoaView.mm index 6d57aaff..e5648bbd 100644 --- a/StCore/StCocoaView.mm +++ b/StCore/StCocoaView.mm @@ -348,17 +348,17 @@ - (void ) scrollWheel: (NSEvent* ) theEvent { CGFloat aDeltaY = [theEvent deltaY]; if(!stAreEqual(aDeltaX, 0.0f, 0.01f)) { myStEvent.Scroll.StepsX = aDeltaX > 0.0f ? -1 : 1; - myStEvent.Scroll.DeltaX = 10.0f * myStEvent.Scroll.StepsX; + myStEvent.Scroll.DeltaX = myStEvent.Scroll.StepsX; } if(!stAreEqual(aDeltaY, 0.0f, 0.01f)) { myStEvent.Scroll.StepsY = aDeltaY > 0.0f ? 1 : -1; - myStEvent.Scroll.DeltaY = 10.0f * myStEvent.Scroll.StepsY; + myStEvent.Scroll.DeltaY = myStEvent.Scroll.StepsY; } if(myIsLionOS && [theEvent hasPreciseScrollingDeltas]) { - myStEvent.Scroll.DeltaX = [theEvent scrollingDeltaX]; - myStEvent.Scroll.DeltaY = [theEvent scrollingDeltaY]; + myStEvent.Scroll.DeltaX = 0.1f * [theEvent scrollingDeltaX]; + myStEvent.Scroll.DeltaY = 0.1f * [theEvent scrollingDeltaY]; } //if([theEvent subtype] == NSMouseEventSubtype) { diff --git a/StCore/StWindowImpl.cpp b/StCore/StWindowImpl.cpp index 5025d8d6..4809cf1f 100644 --- a/StCore/StWindowImpl.cpp +++ b/StCore/StWindowImpl.cpp @@ -97,6 +97,10 @@ StWindowImpl::StWindowImpl(const StHandle& theResMgr, myIsMouseMoved(false) { stMemZero(&attribs, sizeof(attribs)); stMemZero(&signals, sizeof(signals)); + myStEvent .Type = stEvent_None; + myStEvent2 .Type = stEvent_None; + myStEventAux.Type = stEvent_None; + myScrollAcc.reset(); attribs.IsNoDecor = false; attribs.IsStereoOutput = false; attribs.IsGlStereo = false; diff --git a/StCore/StWindowImpl.h b/StCore/StWindowImpl.h index 4b74cc19..2459b865 100644 --- a/StCore/StWindowImpl.h +++ b/StCore/StWindowImpl.h @@ -477,6 +477,7 @@ class StWindowImpl { StEvent myStEvent; //!< temporary event object (to be used in message loop thread) StEvent myStEvent2; //!< temporary event object (to be used in message loop thread) StEvent myStEventAux; //!< extra temporary event object (to be used in StWindow creation thread) + StScrollEvent myScrollAcc; //!< extra temporary event object accumulating mouse scroll events int myAlignDL; //!< extra window shift applied for alignment (left) int myAlignDR; //!< extra window shift applied for alignment (right) int myAlignDT; //!< extra window shift applied for alignment (top) diff --git a/StCore/StWindowImplLin.cpp b/StCore/StWindowImplLin.cpp index 79cfd523..466fab96 100644 --- a/StCore/StWindowImplLin.cpp +++ b/StCore/StWindowImplLin.cpp @@ -962,7 +962,7 @@ void StWindowImpl::processEvents() { myStEvent.Scroll.StepsX = 0; myStEvent.Scroll.StepsY = aBtnEvent->button == 4 ? 1 : -1; myStEvent.Scroll.DeltaX = 0.0; - myStEvent.Scroll.DeltaY = 10.0f * myStEvent.Scroll.StepsY; + myStEvent.Scroll.DeltaY = myStEvent.Scroll.StepsY; myStEvent.Scroll.IsFromMultiTouch = false; signals.onScroll->emit(myStEvent.Scroll); break; diff --git a/StCore/StWindowImplWin.cpp b/StCore/StWindowImplWin.cpp index abcb53a3..82d1c6d5 100644 --- a/StCore/StWindowImplWin.cpp +++ b/StCore/StWindowImplWin.cpp @@ -875,25 +875,32 @@ LRESULT StWindowImpl::stWndProc(HWND theWin, UINT uMsg, WPARAM wParam, LPARAM lP return 0; } case WM_MOUSEWHEEL: // vertical wheel - //case WM_MOUSEHWHEEL: // horizontal wheel (only Vista+) + case WM_MOUSEHWHEEL: // horizontal wheel (only Vista+) { const StRectI_t aWinRect = getPlacement(); int aMouseXPx = int(short(LOWORD(lParam))) - aWinRect.left(); int aMouseYPx = int(short(HIWORD(lParam))) - aWinRect.top(); - int aZDelta = GET_WHEEL_DELTA_WPARAM(wParam); // / WHEEL_DELTA; - //if(GET_X_LPARAM(lParam) != 0) - - myStEvent.Type = stEvent_Scroll; - myStEvent.Scroll.Time = getEventTime(myEvent.time); - myStEvent.Scroll.PointX = double(aMouseXPx) / double(aWinRect.width()); - myStEvent.Scroll.PointY = double(aMouseYPx) / double(aWinRect.height()); - myStEvent.Scroll.StepsX = 0; - myStEvent.Scroll.StepsY = (aZDelta > 0) ? 1 : -1; - myStEvent.Scroll.DeltaX = 0.0; - myStEvent.Scroll.DeltaY = 10.0f * myStEvent.Scroll.StepsY; - myStEvent.Scroll.IsFromMultiTouch = false; - + const bool isVert = (uMsg == WM_MOUSEWHEEL); + const int aZDelta = GET_WHEEL_DELTA_WPARAM(wParam); + const float aDeltaSt = float(aZDelta) / float(WHEEL_DELTA); + + myStEvent.Scroll.init(getEventTime(myEvent.time), + double(aMouseXPx) / double(aWinRect.width()), + double(aMouseYPx) / double(aWinRect.height()), + !isVert ? aDeltaSt : 0.0f, + isVert ? aDeltaSt : 0.0f, + false); + if((myStEvent.Scroll.Time - myScrollAcc.Time) > 0.1 + || std::abs(aMouseXPx - (int)myScrollAcc.PointX) > 10 + || std::abs(aMouseYPx - (int)myScrollAcc.PointY) > 10) { + myScrollAcc.reset(); + } + myScrollAcc.Time = myStEvent.Scroll.Time; + myScrollAcc.PointX = aMouseXPx; + myScrollAcc.PointY = aMouseYPx; + myStEvent.Scroll.StepsX = myScrollAcc.accumulateStepsX(!isVert ? aZDelta : 0, WHEEL_DELTA); + myStEvent.Scroll.StepsY = myScrollAcc.accumulateStepsY( isVert ? aZDelta : 0, WHEEL_DELTA); myEventsBuffer.append(myStEvent); return 0; } diff --git a/StGLWidgets/StGLImageRegion.cpp b/StGLWidgets/StGLImageRegion.cpp index 1c5ab987..d5c58040 100644 --- a/StGLWidgets/StGLImageRegion.cpp +++ b/StGLWidgets/StGLImageRegion.cpp @@ -1011,34 +1011,32 @@ bool StGLImageRegion::doScroll(const StScrollEvent& theEvent) { return false; } - const GLfloat SCALE_STEPS = fabs(theEvent.DeltaY) * 0.01f; - if(theEvent.DeltaY > 0.001f) { - if((myKeyFlags & ST_VF_CONTROL) == ST_VF_CONTROL) { - if((myKeyFlags & ST_VF_SHIFT) == ST_VF_SHIFT) { + if((myKeyFlags & ST_VF_CONTROL) == ST_VF_CONTROL) { + if(theEvent.StepsY == 0) { + return false; + } + if((myKeyFlags & ST_VF_SHIFT) == ST_VF_SHIFT) { + if(theEvent.StepsY > 0) { doParamsSepZDec(0.01); } else { - doParamsSepX(size_t(-1)); - } - return true; - } else if((myKeyFlags & ST_VF_SHIFT) == ST_VF_SHIFT) { - doParamsSepY(size_t(-1)); - return true; - } - - scaleAt(aCursor, SCALE_STEPS); - } else if(theEvent.DeltaY < -0.001f) { - if((myKeyFlags & ST_VF_CONTROL) == ST_VF_CONTROL) { - if((myKeyFlags & ST_VF_SHIFT) == ST_VF_SHIFT) { doParamsSepZInc(0.01); - } else { - doParamsSepX(size_t(1)); } - return true; - } else if((myKeyFlags & ST_VF_SHIFT) == ST_VF_SHIFT) { - doParamsSepY(size_t(1)); - return true; + } else { + doParamsSepX(theEvent.StepsY > 0 ? size_t(-1) : size_t(1)); } + return true; + } else if((myKeyFlags & ST_VF_SHIFT) == ST_VF_SHIFT) { + if(theEvent.StepsY == 0) { + return false; + } + doParamsSepY(theEvent.StepsY > 0 ? size_t(-1) : size_t(1)); + return true; + } + const GLfloat SCALE_STEPS = fabs(theEvent.DeltaY) * 0.1f; + if(theEvent.DeltaY > 0.0001f) { + scaleAt(aCursor, SCALE_STEPS); + } else if(theEvent.DeltaY < -0.0001f) { scaleAt(aCursor, -SCALE_STEPS); } return true; diff --git a/StGLWidgets/StGLScrollArea.cpp b/StGLWidgets/StGLScrollArea.cpp index e591df1c..62fa6f98 100644 --- a/StGLWidgets/StGLScrollArea.cpp +++ b/StGLWidgets/StGLScrollArea.cpp @@ -27,7 +27,8 @@ StGLScrollArea::StGLScrollArea(StGLWidget* theParent, myDragYCumul(0), myFlingAccel((double )myRoot->scale(200)), myFlingYSpeed(0.0), - myFlingYDone(0) { + myFlingYDone(0), + myScrollYAccum(0.0f) { // } @@ -298,11 +299,12 @@ bool StGLScrollArea::doScroll(const StScrollEvent& theEvent) { return true; } - int aDeltaY = (int )fabs(theEvent.DeltaY * 2.0f); - if(theEvent.DeltaY > 0.001f) { - doScroll( myRoot->scale(aDeltaY)); - } else if(theEvent.DeltaY < -0.001f) { - doScroll(-myRoot->scale(aDeltaY)); + myScrollYAccum += theEvent.DeltaY * 20.0f; + const int aDeltaY = (int )myScrollYAccum; + if(aDeltaY != 0) { + myScrollYAccum -= float(aDeltaY); + const int aDeltaScaled = myRoot->scale(std::abs(aDeltaY)); + doScroll(aDeltaY > 0 ? aDeltaScaled : -aDeltaScaled); } return true; } diff --git a/StOutPageFlip/StDXNVWindow.cpp b/StOutPageFlip/StDXNVWindow.cpp index fcd2d9ca..7f98fdb6 100644 --- a/StOutPageFlip/StDXNVWindow.cpp +++ b/StOutPageFlip/StDXNVWindow.cpp @@ -112,19 +112,22 @@ LRESULT StDXNVWindow::wndProcFunction(HWND theWnd, LPARAM theParamL) { // we do stupid checks here... if(myStWin->isFullScreen() && myStWin->isStereoOutput()) { - if(theMsg == WM_MOUSEWHEEL) { - int zDelta = GET_WHEEL_DELTA_WPARAM(theParamW); + if(theMsg == WM_MOUSEWHEEL + || theMsg == WM_MOUSEHWHEEL) { + const bool isVert = (theMsg == WM_MOUSEWHEEL); + const int aZDelta = GET_WHEEL_DELTA_WPARAM(theParamW); + const int aNbSteps = (aZDelta > 0) ? 1 : -1; + const float aDeltaSt = float(aZDelta) / float(WHEEL_DELTA); const StPointD_t aPnt = myStWin->getMousePos(); StEvent anEvent; - anEvent.Type = stEvent_Scroll; - anEvent.Scroll.Time = 0.0; //getEventTime(myEvent.time); - anEvent.Scroll.PointX = aPnt.x(); - anEvent.Scroll.PointY = aPnt.y(); - anEvent.Scroll.StepsX = 0; - anEvent.Scroll.StepsY = (zDelta > 0) ? 1 : -1; - anEvent.Scroll.DeltaX = 0.0; - anEvent.Scroll.DeltaY = 10.0f * anEvent.Scroll.StepsY; - anEvent.Scroll.IsFromMultiTouch = false; + anEvent.Scroll.init(0.0, //getEventTime(myEvent.time); + aPnt.x(), + aPnt.y(), + !isVert ? aDeltaSt : 0.0f, + isVert ? aDeltaSt : 0.0f, + false); + anEvent.Scroll.StepsX = !isVert ? aNbSteps : 0; + anEvent.Scroll.StepsY = isVert ? aNbSteps : 0; myStWin->post(anEvent); } diff --git a/include/StCore/StEvent.h b/include/StCore/StEvent.h index 0e26d5b3..6fc861d5 100644 --- a/include/StCore/StEvent.h +++ b/include/StCore/StEvent.h @@ -186,6 +186,65 @@ struct StScrollEvent { float DeltaY; //!< precise delta for vertical scroll bool IsFromMultiTouch; //!< when true, scrolling is simulated from multi-touch gesture by system (OS X) and touches will come in parallel + /** + * Reset event. + */ + void reset() { + Type = stEvent_Scroll; + Time = 0.0; + PointX = 0.0; + PointY = 0.0; + StepsX = 0; + StepsY = 0; + DeltaX = 0.0f; + DeltaY = 0.0f; + IsFromMultiTouch = false; + } + + /** + * Initialize event. + */ + void init(double theTime, + double thePointX, + double thePointY, + float theDeltaX, + float theDeltaY, + bool theIsFromMultiTouch) { + Type = stEvent_Scroll; + Time = theTime; + PointX = thePointX; + PointY = thePointY; + StepsX = 0; + StepsY = 0; + DeltaX = theDeltaX; + DeltaY = theDeltaY; + IsFromMultiTouch = theIsFromMultiTouch; + } + + /** + * Compute accumulated integer steps from X scroll event. + */ + int accumulateStepsX(int theInc, int theStepSize) { return accumulateSteps(StepsX, theInc, theStepSize); } + + /** + * Compute accumulated integer steps from Y scroll event. + */ + int accumulateStepsY(int theInc, int theStepSize) { return accumulateSteps(StepsY, theInc, theStepSize); } + + /** + * Compute accumulated integer steps from scroll event. + */ + static int accumulateSteps(int& theAcc, int theInc, int theStepSize) { + theAcc += theInc; + int aNbSteps = 0; + for(; theAcc <= -theStepSize; theAcc += theStepSize) { + --aNbSteps; + } + for(; theAcc >= theStepSize; theAcc -= theStepSize) { + ++aNbSteps; + } + return aNbSteps; + } }; /** diff --git a/include/StGLWidgets/StGLScrollArea.h b/include/StGLWidgets/StGLScrollArea.h index edaa2206..20aea52f 100644 --- a/include/StGLWidgets/StGLScrollArea.h +++ b/include/StGLWidgets/StGLScrollArea.h @@ -72,6 +72,7 @@ class StGLScrollArea : public StGLWidget { StTimer myFlingTimer; //!< timer for dragging inertia double myFlingYSpeed; //!< the dragging velocity for inertial scrolling int myFlingYDone; //!< already animated inertial scrolling + float myScrollYAccum;//!< accumulated scroll event value };