From 94fdd6aa4368fe1eb6e8f81cbabceb00973bca1a Mon Sep 17 00:00:00 2001 From: PixelyIon Date: Wed, 31 Aug 2022 23:43:02 +0530 Subject: [PATCH] Fix HID touch points not being removed from screen Tapping anything in titles that supported touch (such as Puyo Puyo Tetris or Sonic Mania) wouldn't work due to the first touch point never being removed from the screen, it is supposed to be removed after a 3 frame delay from the touch ending. This commit introduces a mechanism to "time-out" touch points which counts down during the shared memory updates and removes them from the screen after a specified timeout duration. --- app/src/main/cpp/skyline/input/touch.cpp | 33 ++++++++++++++++++++++++ app/src/main/cpp/skyline/input/touch.h | 3 +++ 2 files changed, 36 insertions(+) diff --git a/app/src/main/cpp/skyline/input/touch.cpp b/app/src/main/cpp/skyline/input/touch.cpp index 79bb0d43..9951b5ea 100644 --- a/app/src/main/cpp/skyline/input/touch.cpp +++ b/app/src/main/cpp/skyline/input/touch.cpp @@ -9,6 +9,7 @@ namespace skyline::input { } void TouchManager::Activate() { + std::scoped_lock lock{mutex}; if (!activated) { activated = true; SetState({}); @@ -16,13 +17,21 @@ namespace skyline::input { } void TouchManager::SetState(span touchPoints) { + std::scoped_lock lock{mutex}; + touchPoints = touchPoints.first(std::min(touchPoints.size(), screenState.data.size())); screenState.touchCount = touchPoints.size(); for (size_t i{}; i < touchPoints.size(); i++) { const auto &host{touchPoints[i]}; auto &guest{screenState.data[i]}; + + constexpr uint8_t TouchPointTimeout{3}; //!< The amount of frames an ended point is expected to be active before it is removed from the screen + guest.attribute.raw = static_cast(host.attribute); + if (guest.attribute.end) + pointTimeout[i] = TouchPointTimeout; + guest.index = static_cast(host.id); guest.positionX = static_cast(host.x); guest.positionY = static_cast(host.y); @@ -37,6 +46,30 @@ namespace skyline::input { } void TouchManager::UpdateSharedMemory() { + std::scoped_lock lock{mutex}; + + for (size_t i{}; i < screenState.data.size(); i++) { + // Remove any touch points which have ended after they are timed out + if (screenState.data[i].attribute.end) { + auto &timeout{pointTimeout[i]}; + if (timeout > 0) { + // Tick the timeout counter + timeout--; + } else { + // Erase the point from the screen + if (i != screenState.data.size() - 1) { + // Move every point after the one being removed to fill the gap + for (size_t j{i + 1}; j < screenState.data.size(); j++) { + screenState.data[j - 1] = screenState.data[j]; + pointTimeout[j - 1] = pointTimeout[j]; + } + i--; + } + screenState.touchCount--; + } + } + } + if (!activated) return; diff --git a/app/src/main/cpp/skyline/input/touch.h b/app/src/main/cpp/skyline/input/touch.h index 16ac2b0f..1605bf74 100644 --- a/app/src/main/cpp/skyline/input/touch.h +++ b/app/src/main/cpp/skyline/input/touch.h @@ -30,7 +30,10 @@ namespace skyline::input { const DeviceState &state; bool activated{}; TouchScreenSection §ion; + + std::recursive_mutex mutex; TouchScreenState screenState{}; //!< The current state of the touch screen + std::array pointTimeout; //!< A frame timeout counter for each point which has ended (according to it's attribute), when it reaches 0 the point is removed from the screen public: /**