From dd28eba39f4dcdcc877e7b676bf4df15ae6b9ae6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 3 Sep 2026 10:29:25 -0600 Subject: [PATCH] Keep swipe gesture buttons held while the finger stays down The swipe directions only fired while the finger was actually moving, so holding a direction meant sliding around forever. Now a swiped direction stays held until the finger lifts, or until the opposite direction is swiped. Also release any held direction if the touch controls are torn down mid-gesture. Fixes #20601 Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01JvJR8oJNSCimCM9KXVLjfq --- UI/GamepadEmu.cpp | 32 ++++++++++++++++++++++++++++---- UI/GamepadEmu.h | 1 + 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/UI/GamepadEmu.cpp b/UI/GamepadEmu.cpp index d49edbfdf3..49909d7083 100644 --- a/UI/GamepadEmu.cpp +++ b/UI/GamepadEmu.cpp @@ -1149,6 +1149,7 @@ const GestureControlConfig &GestureGamepad::GetZone() { } GestureGamepad::~GestureGamepad() { + ReleaseHeldSwipeKeys(); if (dragPointerId_ != -1) { g_activeGesturePointers.erase(dragPointerId_); } @@ -1165,6 +1166,24 @@ static bool ValidGestureKeyConfig(int config) { return config > 0 && (size_t)config <= ARRAY_SIZE(GestureKey::keyList); } +// Swipe directions stay held until the finger lifts, so if we go away while one is held - the +// touch controls get rebuilt when settings change, for instance - we have to let go ourselves. +void GestureGamepad::ReleaseHeldSwipeKeys() { + const GestureControlConfig &zone = GetZone(); + const struct { int config; bool *released; } keys[] = { + { zone.iSwipeRight, &swipeRightReleased_ }, + { zone.iSwipeLeft, &swipeLeftReleased_ }, + { zone.iSwipeUp, &swipeUpReleased_ }, + { zone.iSwipeDown, &swipeDownReleased_ }, + }; + for (const auto &key : keys) { + if (!*key.released && ValidGestureKeyConfig(key.config)) { + controlMapper_->PSPKey(DEVICE_ID_TOUCH, GestureKey::keyList[key.config - 1], KeyInputFlags::UP); + } + *key.released = true; + } +} + bool GestureGamepad::Touch(const TouchInput &input) { // See the comment in MultiTouchButton::Touch(). if (input.id < 0 || input.id >= TOUCH_MAX_POINTERS) { @@ -1277,11 +1296,16 @@ void GestureGamepad::Update() { return; } + // Once a direction has been swiped, keep it held as long as the finger stays down, instead of + // letting go the moment the finger stops moving - otherwise you can't hold a direction without + // sliding around forever. Swiping the opposite way still releases it, as does lifting the finger. + const bool stillTouching = dragPointerId_ != -1; + if (ValidGestureKeyConfig(GetZone().iSwipeRight)) { if (dx > th) { controlMapper_->PSPKey(DEVICE_ID_TOUCH, GestureKey::keyList[GetZone().iSwipeRight - 1], KeyInputFlags::DOWN); swipeRightReleased_ = false; - } else if (!swipeRightReleased_) { + } else if (!swipeRightReleased_ && (!stillTouching || dx < -th)) { controlMapper_->PSPKey(DEVICE_ID_TOUCH, GestureKey::keyList[GetZone().iSwipeRight -1], KeyInputFlags::UP); swipeRightReleased_ = true; } @@ -1290,7 +1314,7 @@ void GestureGamepad::Update() { if (dx < -th) { controlMapper_->PSPKey(DEVICE_ID_TOUCH, GestureKey::keyList[GetZone().iSwipeLeft - 1], KeyInputFlags::DOWN); swipeLeftReleased_ = false; - } else if (!swipeLeftReleased_) { + } else if (!swipeLeftReleased_ && (!stillTouching || dx > th)) { controlMapper_->PSPKey(DEVICE_ID_TOUCH, GestureKey::keyList[GetZone().iSwipeLeft - 1], KeyInputFlags::UP); swipeLeftReleased_ = true; } @@ -1299,7 +1323,7 @@ void GestureGamepad::Update() { if (dy < -th) { controlMapper_->PSPKey(DEVICE_ID_TOUCH, GestureKey::keyList[GetZone().iSwipeUp - 1], KeyInputFlags::DOWN); swipeUpReleased_ = false; - } else if (!swipeUpReleased_) { + } else if (!swipeUpReleased_ && (!stillTouching || dy > th)) { controlMapper_->PSPKey(DEVICE_ID_TOUCH, GestureKey::keyList[GetZone().iSwipeUp - 1], KeyInputFlags::UP); swipeUpReleased_ = true; } @@ -1308,7 +1332,7 @@ void GestureGamepad::Update() { if (dy > th) { controlMapper_->PSPKey(DEVICE_ID_TOUCH, GestureKey::keyList[GetZone().iSwipeDown - 1], KeyInputFlags::DOWN); swipeDownReleased_ = false; - } else if (!swipeDownReleased_) { + } else if (!swipeDownReleased_ && (!stillTouching || dy < -th)) { controlMapper_->PSPKey(DEVICE_ID_TOUCH, GestureKey::keyList[GetZone().iSwipeDown - 1], KeyInputFlags::UP); swipeDownReleased_ = true; } diff --git a/UI/GamepadEmu.h b/UI/GamepadEmu.h index ce8463c100..03ce687f8d 100644 --- a/UI/GamepadEmu.h +++ b/UI/GamepadEmu.h @@ -223,6 +223,7 @@ protected: private: const GestureControlConfig &GetZone(); + void ReleaseHeldSwipeKeys(); int zoneIndex_; float lastX_ = 0.0f;