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.
This commit is contained in:
PixelyIon 2022-08-31 23:43:02 +05:30
parent 70ad4498a2
commit 94fdd6aa43
2 changed files with 36 additions and 0 deletions

View File

@ -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<TouchScreenPoint> 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<u32>(host.attribute);
if (guest.attribute.end)
pointTimeout[i] = TouchPointTimeout;
guest.index = static_cast<u32>(host.id);
guest.positionX = static_cast<u32>(host.x);
guest.positionY = static_cast<u32>(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;

View File

@ -30,7 +30,10 @@ namespace skyline::input {
const DeviceState &state;
bool activated{};
TouchScreenSection &section;
std::recursive_mutex mutex;
TouchScreenState screenState{}; //!< The current state of the touch screen
std::array<uint8_t, 16> 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:
/**