Add "InputRepeating" when holding a navigation button in the config menu

This commit is contained in:
Maschell 2026-04-29 08:33:18 +02:00
parent 9781f6e846
commit f9e8bf6b82
6 changed files with 83 additions and 15 deletions

View File

@ -91,9 +91,12 @@ ConfigSubState CategoryRenderer::UpdateStateMain(const Input &input, const WUPSC
const int32_t prevSelectedItem = mCursorPos;
if (mIsItemMovementAllowed) {
if (input.data.buttons_d & Input::eButtons::BUTTON_DOWN) {
uint32_t navMask = Input::eButtons::BUTTON_UP | Input::eButtons::BUTTON_DOWN;
uint32_t actionButton = mNavRepeater.update(input, navMask);
if (actionButton & Input::eButtons::BUTTON_DOWN) {
mCursorPos++;
} else if (input.data.buttons_d & Input::eButtons::BUTTON_UP) {
} else if (actionButton & Input::eButtons::BUTTON_UP) {
mCursorPos--;
} else if (input.data.buttons_d & Input::eButtons::BUTTON_A) {
if (mCursorPos < static_cast<int32_t>(mCat->getCategories().size())) {
@ -107,6 +110,8 @@ ConfigSubState CategoryRenderer::UpdateStateMain(const Input &input, const WUPSC
return SUB_STATE_RUNNING;
}
}
} else {
mNavRepeater.reset();
}
if (mCursorPos < 0) {

View File

@ -2,6 +2,7 @@
#include "ConfigDefines.h"
#include "ConfigDisplayItem.h"
#include "InputRepeater.h"
#include <wups/config.h>
@ -57,4 +58,6 @@ private:
bool mFirstFrame = true;
bool mIsRoot = false;
bool mNeedsRedraw = true;
InputRepeater mNavRepeater;
};

View File

@ -103,13 +103,10 @@ void ConfigRenderer::ResetNeedsRedraw() {
void ConfigRenderer::RequestRedraw() {
mNeedRedraw = true;
}
ConfigSubState ConfigRenderer::UpdateStateMain(const Input &input) {
if (!mListState) return SUB_STATE_ERROR;
auto &configs = GetDisplayedConfigList();
const auto prevSelectedItem = mCursorPos;
auto totalElementSize = (int32_t) configs.size();
if (!mListState) {
return SUB_STATE_ERROR;
}
// Delegate specific inputs to the State
bool inputHandled = mListState->HandleInput(*this, input);
@ -122,16 +119,23 @@ ConfigSubState ConfigRenderer::UpdateStateMain(const Input &input) {
return SUB_STATE_RUNNING;
}
// Handle Navigation (Common to all states)
if (input.data.buttons_d & Input::eButtons::BUTTON_DOWN) {
const auto prevSelectedItem = mCursorPos;
auto &configs = GetDisplayedConfigList();
auto totalElementSize = (int32_t) configs.size();
uint32_t navMask = Input::eButtons::BUTTON_UP | Input::eButtons::BUTTON_DOWN |
Input::eButtons::BUTTON_LEFT | Input::eButtons::BUTTON_RIGHT;
uint32_t actionButton = mNavRepeater.update(input, navMask);
if (actionButton & Input::eButtons::BUTTON_DOWN) {
mCursorPos++;
} else if (input.data.buttons_d & Input::eButtons::BUTTON_LEFT) {
} else if (actionButton & Input::eButtons::BUTTON_LEFT) {
mCursorPos -= MAX_BUTTONS_ON_SCREEN - 1;
if (mCursorPos < 0) mCursorPos = 0;
} else if (input.data.buttons_d & Input::eButtons::BUTTON_RIGHT) {
} else if (actionButton & Input::eButtons::BUTTON_RIGHT) {
mCursorPos += MAX_BUTTONS_ON_SCREEN - 1;
if (mCursorPos >= totalElementSize) mCursorPos = totalElementSize - 1;
} else if (input.data.buttons_d & Input::eButtons::BUTTON_UP) {
} else if (actionButton & Input::eButtons::BUTTON_UP) {
mCursorPos--;
}

View File

@ -2,6 +2,7 @@
#include "ConfigDefines.h"
#include "ConfigDisplayItem.h"
#include "InputRepeater.h"
#include <wups/config.h>
@ -80,4 +81,6 @@ private:
bool mNeedRedraw = true;
bool mPluginListDirty = false;
bool mLastInputWasOnWiimote = false;
InputRepeater mNavRepeater;
};

View File

@ -217,8 +217,8 @@ void ConfigUtils::displayMenu() {
renderer.ResetNeedsRedraw();
auto diffTime = OSTicksToMicroseconds(OSGetTime() - startTime);
if (diffTime < 16000) {
OSSleepTicks(OSMicrosecondsToTicks(16000 - diffTime));
if (diffTime < 33000) {
OSSleepTicks(OSMicrosecondsToTicks(33000 - diffTime));
}
}

View File

@ -0,0 +1,53 @@
#pragma once
#include "utils/input/Input.h"
#include <cstdint>
class InputRepeater {
public:
// thresholdDelay: frames to wait before starting repeat (e.g., 15)
// repeatRate: frames between repeats (e.g., 6)
explicit InputRepeater(uint32_t thresholdDelay = 15, uint32_t repeatRate = 6)
: mThresholdDelay(thresholdDelay), mRepeatRate(repeatRate) {}
uint32_t update(const Input &input, uint32_t mask) {
uint32_t currentPressed = input.data.buttons_d & mask;
uint32_t currentHeld = input.data.buttons_h & mask;
if (currentPressed) {
// New press: reset and return the button immediately
mScrollTimer = 0;
mHeldButton = currentPressed;
mInRepeatMode = false;
return currentPressed;
}
if (currentHeld && (currentHeld == mHeldButton)) {
mScrollTimer++;
uint32_t threshold = mInRepeatMode ? mRepeatRate : mThresholdDelay;
if (mScrollTimer >= threshold) {
mScrollTimer = 0;
mInRepeatMode = true;
return currentHeld;
}
} else {
// Button released or changed
reset();
}
return 0; // No action this frame
}
void reset() {
mScrollTimer = 0;
mHeldButton = 0;
mInRepeatMode = false;
}
private:
uint32_t mThresholdDelay;
uint32_t mRepeatRate;
uint32_t mScrollTimer = 0;
uint32_t mHeldButton = 0;
bool mInRepeatMode = false;
};