feat(service_menu): navegacio amb mando (dpad, stick, fire = enter, accelerate = back)
ServiceMenu::handleEvent ara accepta tambe SDL_EVENT_GAMEPAD_BUTTON_DOWN i SDL_EVENT_GAMEPAD_AXIS_MOTION. Mapeig: dpad UP/DOWN/LEFT/RIGHT mouen el cursor, el boto FIRE configurat per qualsevol jugador equival a ENTER (activa l'item), ACCELERATE equival a BACK (popPage). El stick esquerre fa nav amb edge-detect: cal tornar a centre per disparar una altra entrada. GlobalEvents::forwardToServiceMenu envia tots aquests events al menu quan esta obert. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -718,10 +718,52 @@ namespace System {
|
||||
}
|
||||
}
|
||||
|
||||
auto ServiceMenu::handleEvent(const SDL_Event& event) -> bool {
|
||||
if (!open_ || stack_.empty() || event.type != SDL_EVENT_KEY_DOWN) {
|
||||
namespace {
|
||||
|
||||
// Llindar de stick per a navegacio de menu (mig camp del rang ±32767).
|
||||
// Mes baix que el del joc (30000) per a una resposta mes agil al menu.
|
||||
constexpr Sint16 MENU_STICK_THRESHOLD = 16384;
|
||||
|
||||
// Retorna true si el codi de boto SDL coincideix amb l'accio
|
||||
// configurada per algun dels dos jugadors (es a dir, el boto te el
|
||||
// mateix codi al binding de FIRE o ACCELERATE del pad emissor).
|
||||
auto buttonMatchesAction(SDL_JoystickID which, int button, InputAction action) -> bool {
|
||||
const auto* input = Input::get();
|
||||
if (input == nullptr) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
auto pad = input->getPlayerGamepad(i);
|
||||
if (!pad || pad->instance_id != which) {
|
||||
continue;
|
||||
}
|
||||
auto it = pad->bindings.find(action);
|
||||
if (it != pad->bindings.end() && it->second.button == button) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
auto ServiceMenu::handleEvent(const SDL_Event& event) -> bool {
|
||||
if (!open_ || stack_.empty()) {
|
||||
return false;
|
||||
}
|
||||
if (event.type == SDL_EVENT_KEY_DOWN) {
|
||||
return handleKeyDown(event);
|
||||
}
|
||||
if (event.type == SDL_EVENT_GAMEPAD_BUTTON_DOWN) {
|
||||
return handleGamepadButton(event);
|
||||
}
|
||||
if (event.type == SDL_EVENT_GAMEPAD_AXIS_MOTION) {
|
||||
return handleGamepadAxis(event);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
auto ServiceMenu::handleKeyDown(const SDL_Event& event) -> bool {
|
||||
switch (event.key.scancode) {
|
||||
case SDL_SCANCODE_UP:
|
||||
moveCursor(-1);
|
||||
@@ -747,6 +789,68 @@ namespace System {
|
||||
}
|
||||
}
|
||||
|
||||
auto ServiceMenu::handleGamepadButton(const SDL_Event& event) -> bool {
|
||||
const int BTN = static_cast<int>(event.gbutton.button);
|
||||
if (BTN == SDL_GAMEPAD_BUTTON_DPAD_UP) {
|
||||
moveCursor(-1);
|
||||
return true;
|
||||
}
|
||||
if (BTN == SDL_GAMEPAD_BUTTON_DPAD_DOWN) {
|
||||
moveCursor(+1);
|
||||
return true;
|
||||
}
|
||||
if (BTN == SDL_GAMEPAD_BUTTON_DPAD_LEFT) {
|
||||
changeValue(-1);
|
||||
return true;
|
||||
}
|
||||
if (BTN == SDL_GAMEPAD_BUTTON_DPAD_RIGHT) {
|
||||
changeValue(+1);
|
||||
return true;
|
||||
}
|
||||
// Botons d'accio per al pad emissor: FIRE = ENTER, ACCELERATE = BACK.
|
||||
if (buttonMatchesAction(event.gbutton.which, BTN, InputAction::SHOOT)) {
|
||||
activateCurrent();
|
||||
return true;
|
||||
}
|
||||
if (buttonMatchesAction(event.gbutton.which, BTN, InputAction::THRUST)) {
|
||||
popPage();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
auto ServiceMenu::handleGamepadAxis(const SDL_Event& event) -> bool {
|
||||
const auto AXIS = static_cast<SDL_GamepadAxis>(event.gaxis.axis);
|
||||
const Sint16 VAL = event.gaxis.value;
|
||||
if (AXIS == SDL_GAMEPAD_AXIS_LEFTX) {
|
||||
const bool LEFT_NOW = VAL < -MENU_STICK_THRESHOLD;
|
||||
const bool RIGHT_NOW = VAL > MENU_STICK_THRESHOLD;
|
||||
if (LEFT_NOW && !stick_left_held_) {
|
||||
changeValue(-1);
|
||||
}
|
||||
if (RIGHT_NOW && !stick_right_held_) {
|
||||
changeValue(+1);
|
||||
}
|
||||
stick_left_held_ = LEFT_NOW;
|
||||
stick_right_held_ = RIGHT_NOW;
|
||||
return true;
|
||||
}
|
||||
if (AXIS == SDL_GAMEPAD_AXIS_LEFTY) {
|
||||
const bool UP_NOW = VAL < -MENU_STICK_THRESHOLD;
|
||||
const bool DOWN_NOW = VAL > MENU_STICK_THRESHOLD;
|
||||
if (UP_NOW && !stick_up_held_) {
|
||||
moveCursor(-1);
|
||||
}
|
||||
if (DOWN_NOW && !stick_down_held_) {
|
||||
moveCursor(+1);
|
||||
}
|
||||
stick_up_held_ = UP_NOW;
|
||||
stick_down_held_ = DOWN_NOW;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
auto ServiceMenu::computeTargetHeight() const -> float {
|
||||
if (stack_.empty()) {
|
||||
return 0.0F;
|
||||
|
||||
Reference in New Issue
Block a user