better controls

This commit is contained in:
2025-10-12 17:29:15 +02:00
parent a6713859b2
commit db88e16aaa
6 changed files with 38 additions and 21 deletions

View File

@@ -1,6 +1,8 @@
#include "cardboy/apps/gameboy_app.hpp" #include "cardboy/apps/gameboy_app.hpp"
#include "cardboy/apps/peanut_gb.h" #include "cardboy/apps/peanut_gb.h"
#include "cardboy/apps/menu_app.hpp"
#include "cardboy/gfx/font16x8.hpp" #include "cardboy/gfx/font16x8.hpp"
#include "cardboy/sdk/app_framework.hpp" #include "cardboy/sdk/app_framework.hpp"
#include "cardboy/sdk/app_system.hpp" #include "cardboy/sdk/app_system.hpp"
@@ -760,6 +762,11 @@ private:
if (roms.empty()) if (roms.empty())
return; return;
if (input.b && !prevInput.b) {
context.requestAppSwitchByName(apps::kMenuAppName);
return;
}
const auto wrapDecrement = [&]() { const auto wrapDecrement = [&]() {
if (selectedIndex == 0) if (selectedIndex == 0)
selectedIndex = roms.size() - 1; selectedIndex = roms.size() - 1;
@@ -822,7 +829,7 @@ private:
} }
font16x8::drawText(framebuffer, 16, framebuffer.height() - 52, "A/START PLAY", 1, true, 1); font16x8::drawText(framebuffer, 16, framebuffer.height() - 52, "A/START PLAY", 1, true, 1);
font16x8::drawText(framebuffer, 16, framebuffer.height() - 32, "SELECT RESCAN", 1, true, 1); font16x8::drawText(framebuffer, 16, framebuffer.height() - 32, "B BACK SELECT RESCAN", 1, true, 1);
} }
if (!statusMessage.empty()) { if (!statusMessage.empty()) {

View File

@@ -47,7 +47,7 @@ public:
moveSelection(+1); moveSelection(+1);
} }
const bool launch = (current.a && !previous.a) || (current.select && !previous.select); const bool launch = (current.a && !previous.a) || (current.start && !previous.start);
if (launch) if (launch)
launchSelected(); launchSelected();
@@ -153,7 +153,7 @@ private:
font16x8::drawText(framebuffer, topRightX, 20, indexLabel, 1, true, 0); font16x8::drawText(framebuffer, topRightX, 20, indexLabel, 1, true, 0);
drawPagerDots(); drawPagerDots();
drawCenteredText(framebuffer, framebuffer.height() - 48, "A/SELECT START", 1, 1); drawCenteredText(framebuffer, framebuffer.height() - 48, "A START APP", 1, 1);
drawCenteredText(framebuffer, framebuffer.height() - 28, "L/R CHOOSE", 1, 1); drawCenteredText(framebuffer, framebuffer.height() - 28, "L/R CHOOSE", 1, 1);
} }

View File

@@ -64,8 +64,8 @@ public:
moved = true; moved = true;
} }
const bool togglePressed = (current.a && !previous.a) || (current.select && !previous.select) || const bool togglePressed = (current.a && !previous.a) || (current.start && !previous.start) ||
(current.start && !previous.start); (current.select && !previous.select);
if (togglePressed) if (togglePressed)
handleToggle(); handleToggle();

View File

@@ -61,6 +61,7 @@ private:
AppTimerHandle nextTimerId = 1; AppTimerHandle nextTimerId = 1;
std::uint32_t currentGeneration = 0; std::uint32_t currentGeneration = 0;
InputState lastInputState{}; InputState lastInputState{};
bool suppressInputs = false;
}; };
inline AppTimerHandle AppContext::scheduleTimerInternal(std::uint32_t delay_ms, bool repeat) { inline AppTimerHandle AppContext::scheduleTimerInternal(std::uint32_t delay_ms, bool repeat) {

View File

@@ -13,6 +13,10 @@ namespace {
a.select != b.select || a.start != b.start; a.select != b.select || a.start != b.start;
} }
[[nodiscard]] bool anyButtonPressed(const InputState& state) {
return state.up || state.down || state.left || state.right || state.a || state.b || state.select || state.start;
}
constexpr std::uint32_t kIdlePollMs = 16; constexpr std::uint32_t kIdlePollMs = 16;
template<typename Framebuffer> template<typename Framebuffer>
@@ -71,6 +75,7 @@ bool AppSystem::startAppByIndex(std::size_t index) {
clearTimersForCurrentApp(); clearTimersForCurrentApp();
current = std::move(app); current = std::move(app);
lastInputState = context.input.readState(); lastInputState = context.input.readState();
suppressInputs = true;
StatusBar::instance().setServices(context.services); StatusBar::instance().setServices(context.services);
StatusBar::instance().setCurrentAppName(activeFactory ? activeFactory->name() : ""); StatusBar::instance().setCurrentAppName(activeFactory ? activeFactory->name() : "");
current->onStart(); current->onStart();
@@ -94,7 +99,11 @@ void AppSystem::run() {
const InputState inputNow = context.input.readState(); const InputState inputNow = context.input.readState();
const bool consumedByStatusToggle = StatusBar::instance().handleToggleInput(inputNow, lastInputState); const bool consumedByStatusToggle = StatusBar::instance().handleToggleInput(inputNow, lastInputState);
if (!consumedByStatusToggle && inputsDiffer(inputNow, lastInputState)) { if (suppressInputs) {
lastInputState = inputNow;
if (!anyButtonPressed(inputNow))
suppressInputs = false;
} else if (!consumedByStatusToggle && inputsDiffer(inputNow, lastInputState)) {
AppEvent evt{}; AppEvent evt{};
evt.type = AppEventType::Button; evt.type = AppEventType::Button;
evt.timestamp_ms = now; evt.timestamp_ms = now;