diff --git a/reg/DCS.reg b/reg/DCS.reg index 464eed4..13577d7 100644 Binary files a/reg/DCS.reg and b/reg/DCS.reg differ diff --git a/src/APILayer/APILayer.cpp b/src/APILayer/APILayer.cpp index 801f9d4..046a361 100644 --- a/src/APILayer/APILayer.cpp +++ b/src/APILayer/APILayer.cpp @@ -345,10 +345,8 @@ XrResult APILayer::xrWaitFrame( rightHand.mActions.mPrimary = r.mActions.mPrimary; rightHand.mActions.mSecondary = r.mActions.mSecondary; } - if (Config::PinchToScroll) { - leftHand.mActions.mValueChange = l.mActions.mValueChange; - rightHand.mActions.mValueChange = r.mActions.mValueChange; - } + leftHand.mActions.mValueChange = l.mActions.mValueChange; + rightHand.mActions.mValueChange = r.mActions.mValueChange; } if (mPointCtrl) { diff --git a/src/APILayer/HandTrackingSource.cpp b/src/APILayer/HandTrackingSource.cpp index 3add0ba..53c2c3f 100644 --- a/src/APILayer/HandTrackingSource.cpp +++ b/src/APILayer/HandTrackingSource.cpp @@ -345,6 +345,41 @@ void HandTrackingSource::UpdateHand(const FrameInfo& frameInfo, Hand* hand) { state.mPose = {}; break; } + +// --- Grab-and-Move Scroll Gesture --- + if (Config::GrabMoveToScroll) { + bool pinchActive = state.mActions.mPrimary; + + if (pinchActive && state.mPose) { + float currentY = state.mPose->position.y; + + if (!hand->mScrolling) { + // Start scroll mode + hand->mScrolling = true; + hand->mLastScrollY = currentY; + } else { + float delta = currentY - hand->mLastScrollY; + + // Apply grab-and-move scroll scale for different applications + delta *= Config::GrabMoveScrollScale; + + // Threshold to avoid jitter + constexpr float scrollThreshold = 0.01f; + + if (delta > scrollThreshold) { + state.mActions.mValueChange = ActionState::ValueChange::Increase; + hand->mLastScrollY = currentY; + } else if (delta < -scrollThreshold) { + state.mActions.mValueChange = ActionState::ValueChange::Decrease; + hand->mLastScrollY = currentY; + } + } + } else { + // Pinch released → stop scrolling + hand->mScrolling = false; + hand->mLastScrollY = 0.0f; + } + } } void HandTrackingSource::InitHandTracker(Hand* hand) { diff --git a/src/APILayer/HandTrackingSource.h b/src/APILayer/HandTrackingSource.h index 77df03d..b71d463 100644 --- a/src/APILayer/HandTrackingSource.h +++ b/src/APILayer/HandTrackingSource.h @@ -45,6 +45,10 @@ class HandTrackingSource final : public InputSource { ActionState mRawActions {}; XrTime mRawActionsSince {}; + + // --- Added for grab‑and‑move scroll --- + float mLastScrollY = 0.0f; + bool mScrolling = false; }; bool mHibernating {false}; diff --git a/src/SettingsApp/HTCCSettingsApp.cpp b/src/SettingsApp/HTCCSettingsApp.cpp index 8889454..9c57879 100644 --- a/src/SettingsApp/HTCCSettingsApp.cpp +++ b/src/SettingsApp/HTCCSettingsApp.cpp @@ -270,9 +270,15 @@ static void OpenXRGUI() { HTCC::Config::SavePinchToClick(); } - if (ToggleSwitch(&HTCC::Config::PinchToScroll).Caption("Pinch to scroll")) { + if (ToggleSwitch(&HTCC::Config::PinchToScroll) + .Caption("Pinch to scroll")) { HTCC::Config::SavePinchToScroll(); } + + if (ToggleSwitch(&HTCC::Config::GrabMoveToScroll) + .Caption("Grab and move to scroll")) { + HTCC::Config::SaveGrabMoveToScroll(); + } } EndVStackPanel(); @@ -469,4 +475,4 @@ int WINAPI wWinMain( }, }, }); -} \ No newline at end of file +} diff --git a/src/lib/Config.h b/src/lib/Config.h index fe6d4b2..08872ae 100644 --- a/src/lib/Config.h +++ b/src/lib/Config.h @@ -66,6 +66,7 @@ enum class HandTrackingHands : DWORD { IT(XrHandJointEXT, HandTrackingAimJoint, XR_HAND_JOINT_INDEX_PROXIMAL_EXT) \ IT(bool, PinchToClick, true) \ IT(bool, PinchToScroll, true) \ + IT(bool, GrabMoveToScroll, false) \ IT(uint16_t, ShortPressLongPressMilliseconds, 200) \ IT(uint16_t, ScrollWheelDelayMilliseconds, 600) \ IT(uint16_t, ScrollWheelIntervalMilliseconds, 50) \ @@ -150,6 +151,7 @@ enum class HandTrackingHands : DWORD { IT(HandTrackingActionHFOV, std::numbers::pi_v / 2) \ IT(HandTrackingHibernateCutoff, std::numbers::pi_v / 8) \ IT(SmoothingFactor, 1.0f) \ + IT(GrabMoveScrollScale, 1.0f) \ IT(LeftEyeFOVLeft, 0.0f) \ IT(LeftEyeFOVRight, 0.0f) \ IT(LeftEyeFOVUp, 0.0f) \