ja permet mapejar botons tipo trigger
This commit is contained in:
@@ -72,6 +72,9 @@ void DefineButtons::handleEvents(const SDL_Event &event) {
|
|||||||
case SDL_EVENT_GAMEPAD_BUTTON_UP:
|
case SDL_EVENT_GAMEPAD_BUTTON_UP:
|
||||||
checkEnd();
|
checkEnd();
|
||||||
break;
|
break;
|
||||||
|
case SDL_EVENT_GAMEPAD_AXIS_MOTION:
|
||||||
|
doControllerAxisMotion(event.gaxis);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -86,6 +89,8 @@ auto DefineButtons::enable(Options::Gamepad *options_gamepad) -> bool {
|
|||||||
index_button_ = 0;
|
index_button_ = 0;
|
||||||
message_shown_ = false;
|
message_shown_ = false;
|
||||||
closing_ = false;
|
closing_ = false;
|
||||||
|
l2_was_pressed_ = false;
|
||||||
|
r2_was_pressed_ = false;
|
||||||
clearButtons();
|
clearButtons();
|
||||||
updateWindowMessage();
|
updateWindowMessage();
|
||||||
|
|
||||||
@@ -104,6 +109,8 @@ void DefineButtons::disable() {
|
|||||||
finished_ = false;
|
finished_ = false;
|
||||||
message_shown_ = false;
|
message_shown_ = false;
|
||||||
closing_ = false;
|
closing_ = false;
|
||||||
|
l2_was_pressed_ = false;
|
||||||
|
r2_was_pressed_ = false;
|
||||||
|
|
||||||
if (window_message_) {
|
if (window_message_) {
|
||||||
window_message_->hide();
|
window_message_->hide();
|
||||||
@@ -125,6 +132,44 @@ void DefineButtons::doControllerButtonDown(const SDL_GamepadButtonEvent &event)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DefineButtons::doControllerAxisMotion(const SDL_GamepadAxisEvent &event) {
|
||||||
|
auto gamepad = input_->getGamepad(event.which);
|
||||||
|
|
||||||
|
if (!gamepad || gamepad != options_gamepad_->instance) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Solo manejamos L2 y R2 como botones con lógica de transición
|
||||||
|
if (event.axis == SDL_GAMEPAD_AXIS_LEFT_TRIGGER) {
|
||||||
|
bool l2_is_pressed_now = event.value > 16384;
|
||||||
|
|
||||||
|
// Solo actuar en la transición de no presionado a presionado
|
||||||
|
if (l2_is_pressed_now && !l2_was_pressed_) {
|
||||||
|
const auto TRIGGER_BUTTON = Input::TRIGGER_L2_AS_BUTTON;
|
||||||
|
if (checkTriggerNotInUse(TRIGGER_BUTTON)) {
|
||||||
|
buttons_.at(index_button_).button = TRIGGER_BUTTON;
|
||||||
|
incIndexButton();
|
||||||
|
updateWindowMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
l2_was_pressed_ = l2_is_pressed_now;
|
||||||
|
|
||||||
|
} else if (event.axis == SDL_GAMEPAD_AXIS_RIGHT_TRIGGER) {
|
||||||
|
bool r2_is_pressed_now = event.value > 16384;
|
||||||
|
|
||||||
|
// Solo actuar en la transición de no presionado a presionado
|
||||||
|
if (r2_is_pressed_now && !r2_was_pressed_) {
|
||||||
|
const auto TRIGGER_BUTTON = Input::TRIGGER_R2_AS_BUTTON;
|
||||||
|
if (checkTriggerNotInUse(TRIGGER_BUTTON)) {
|
||||||
|
buttons_.at(index_button_).button = TRIGGER_BUTTON;
|
||||||
|
incIndexButton();
|
||||||
|
updateWindowMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
r2_was_pressed_ = r2_is_pressed_now;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void DefineButtons::bindButtons(Options::Gamepad *options_gamepad) {
|
void DefineButtons::bindButtons(Options::Gamepad *options_gamepad) {
|
||||||
for (const auto &button : buttons_) {
|
for (const auto &button : buttons_) {
|
||||||
Input::bindGameControllerButton(options_gamepad->instance, button.action, button.button);
|
Input::bindGameControllerButton(options_gamepad->instance, button.action, button.button);
|
||||||
@@ -148,6 +193,12 @@ auto DefineButtons::checkButtonNotInUse(SDL_GamepadButton button) -> bool {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto DefineButtons::checkTriggerNotInUse(SDL_GamepadButton trigger_button) -> bool {
|
||||||
|
return std::ranges::all_of(buttons_, [trigger_button](const auto &b) {
|
||||||
|
return b.button != trigger_button;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void DefineButtons::clearButtons() {
|
void DefineButtons::clearButtons() {
|
||||||
buttons_.clear();
|
buttons_.clear();
|
||||||
buttons_.emplace_back(Lang::getText("[DEFINE_BUTTONS] FIRE_LEFT"), Input::Action::FIRE_LEFT, SDL_GAMEPAD_BUTTON_INVALID);
|
buttons_.emplace_back(Lang::getText("[DEFINE_BUTTONS] FIRE_LEFT"), Input::Action::FIRE_LEFT, SDL_GAMEPAD_BUTTON_INVALID);
|
||||||
|
|||||||
@@ -60,12 +60,16 @@ class DefineButtons {
|
|||||||
bool finished_ = false; // Flag para indicar si ha terminado
|
bool finished_ = false; // Flag para indicar si ha terminado
|
||||||
bool closing_ = false; // Flag para indicar que está cerrando
|
bool closing_ = false; // Flag para indicar que está cerrando
|
||||||
bool message_shown_ = false; // Flag para indicar que ya mostró el mensaje
|
bool message_shown_ = false; // Flag para indicar que ya mostró el mensaje
|
||||||
|
bool l2_was_pressed_ = false; // Estado anterior del trigger L2
|
||||||
|
bool r2_was_pressed_ = false; // Estado anterior del trigger R2
|
||||||
|
|
||||||
// Métodos
|
// Métodos
|
||||||
void incIndexButton();
|
void incIndexButton();
|
||||||
void doControllerButtonDown(const SDL_GamepadButtonEvent &event);
|
void doControllerButtonDown(const SDL_GamepadButtonEvent &event);
|
||||||
|
void doControllerAxisMotion(const SDL_GamepadAxisEvent &event);
|
||||||
void bindButtons(Options::Gamepad *options_gamepad);
|
void bindButtons(Options::Gamepad *options_gamepad);
|
||||||
auto checkButtonNotInUse(SDL_GamepadButton button) -> bool;
|
auto checkButtonNotInUse(SDL_GamepadButton button) -> bool;
|
||||||
|
auto checkTriggerNotInUse(SDL_GamepadButton trigger_button) -> bool;
|
||||||
void clearButtons();
|
void clearButtons();
|
||||||
void checkEnd();
|
void checkEnd();
|
||||||
void updateWindowMessage();
|
void updateWindowMessage();
|
||||||
|
|||||||
@@ -65,6 +65,10 @@ auto Input::checkAction(Action action, bool repeat, bool check_keyboard, std::sh
|
|||||||
if (gamepad != nullptr) {
|
if (gamepad != nullptr) {
|
||||||
success_controller = checkAxisInput(action, gamepad, repeat);
|
success_controller = checkAxisInput(action, gamepad, repeat);
|
||||||
|
|
||||||
|
if (!success_controller) {
|
||||||
|
success_controller = checkTriggerInput(action, gamepad, repeat);
|
||||||
|
}
|
||||||
|
|
||||||
if (!success_controller) {
|
if (!success_controller) {
|
||||||
if (repeat) { // El usuario quiere saber si está pulsada (estado mantenido)
|
if (repeat) { // El usuario quiere saber si está pulsada (estado mantenido)
|
||||||
success_controller = gamepad->bindings[action].is_held;
|
success_controller = gamepad->bindings[action].is_held;
|
||||||
@@ -243,6 +247,54 @@ auto Input::checkAxisInput(Action action, std::shared_ptr<Gamepad> gamepad, bool
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Comprueba los triggers del mando como botones digitales
|
||||||
|
auto Input::checkTriggerInput(Action action, std::shared_ptr<Gamepad> gamepad, bool repeat) -> bool {
|
||||||
|
// Solo manejamos botones específicos que pueden ser triggers
|
||||||
|
if (gamepad->bindings[action].button != SDL_GAMEPAD_BUTTON_INVALID) {
|
||||||
|
// Solo procesamos L2 y R2 como triggers
|
||||||
|
SDL_GamepadButton button = gamepad->bindings[action].button;
|
||||||
|
|
||||||
|
// Verificar si el botón mapeado corresponde a un trigger virtual
|
||||||
|
// (Para esto necesitamos valores especiales que representen L2/R2 como botones)
|
||||||
|
bool trigger_active_now = false;
|
||||||
|
|
||||||
|
// Usamos constantes especiales para L2 y R2 como botones
|
||||||
|
if (button == TRIGGER_L2_AS_BUTTON) { // L2 como botón
|
||||||
|
Sint16 trigger_value = SDL_GetGamepadAxis(gamepad->pad, SDL_GAMEPAD_AXIS_LEFT_TRIGGER);
|
||||||
|
trigger_active_now = trigger_value > TRIGGER_THRESHOLD;
|
||||||
|
} else if (button == TRIGGER_R2_AS_BUTTON) { // R2 como botón
|
||||||
|
Sint16 trigger_value = SDL_GetGamepadAxis(gamepad->pad, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER);
|
||||||
|
trigger_active_now = trigger_value > TRIGGER_THRESHOLD;
|
||||||
|
} else {
|
||||||
|
return false; // No es un trigger
|
||||||
|
}
|
||||||
|
|
||||||
|
// Referencia al binding correspondiente
|
||||||
|
auto &binding = gamepad->bindings[action];
|
||||||
|
|
||||||
|
if (repeat) {
|
||||||
|
// Si se permite repetir, simplemente devolvemos el estado actual
|
||||||
|
return trigger_active_now;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Si no se permite repetir, aplicamos la lógica de transición
|
||||||
|
if (trigger_active_now && !binding.trigger_active) {
|
||||||
|
// Transición de inactivo a activo
|
||||||
|
binding.trigger_active = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!trigger_active_now && binding.trigger_active) {
|
||||||
|
// Transición de activo a inactivo
|
||||||
|
binding.trigger_active = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mantener el estado actual
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void Input::addGamepadMappingsFromFile() {
|
void Input::addGamepadMappingsFromFile() {
|
||||||
if (SDL_AddGamepadMappingsFromFile(gamepad_mappings_file_.c_str()) < 0) {
|
if (SDL_AddGamepadMappingsFromFile(gamepad_mappings_file_.c_str()) < 0) {
|
||||||
std::cout << "Error, could not load " << gamepad_mappings_file_.c_str() << " file: " << SDL_GetError() << std::endl;
|
std::cout << "Error, could not load " << gamepad_mappings_file_.c_str() << " file: " << SDL_GetError() << std::endl;
|
||||||
@@ -280,6 +332,7 @@ void Input::resetInputStates() {
|
|||||||
for (auto &binding : gamepad->bindings) {
|
for (auto &binding : gamepad->bindings) {
|
||||||
binding.second.is_held = false;
|
binding.second.is_held = false;
|
||||||
binding.second.just_pressed = false;
|
binding.second.just_pressed = false;
|
||||||
|
binding.second.trigger_active = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,10 @@ class Input {
|
|||||||
static constexpr bool CHECK_KEYBOARD = true;
|
static constexpr bool CHECK_KEYBOARD = true;
|
||||||
static constexpr bool DO_NOT_CHECK_KEYBOARD = false;
|
static constexpr bool DO_NOT_CHECK_KEYBOARD = false;
|
||||||
|
|
||||||
|
// Constantes para triggers como botones
|
||||||
|
static constexpr SDL_GamepadButton TRIGGER_L2_AS_BUTTON = static_cast<SDL_GamepadButton>(100);
|
||||||
|
static constexpr SDL_GamepadButton TRIGGER_R2_AS_BUTTON = static_cast<SDL_GamepadButton>(101);
|
||||||
|
|
||||||
// Alias para mantener compatibilidad con el código existente
|
// Alias para mantener compatibilidad con el código existente
|
||||||
using Action = InputAction;
|
using Action = InputAction;
|
||||||
|
|
||||||
@@ -39,9 +43,10 @@ class Input {
|
|||||||
bool is_held; // Está pulsada ahora mismo
|
bool is_held; // Está pulsada ahora mismo
|
||||||
bool just_pressed; // Se acaba de pulsar en este fotograma
|
bool just_pressed; // Se acaba de pulsar en este fotograma
|
||||||
bool axis_active; // Estado del eje
|
bool axis_active; // Estado del eje
|
||||||
|
bool trigger_active; // Estado del trigger como botón digital
|
||||||
|
|
||||||
ButtonState(SDL_GamepadButton btn = SDL_GAMEPAD_BUTTON_INVALID, bool is_held = false, bool just_pressed = false, bool axis_act = false)
|
ButtonState(SDL_GamepadButton btn = SDL_GAMEPAD_BUTTON_INVALID, bool is_held = false, bool just_pressed = false, bool axis_act = false)
|
||||||
: button(btn), is_held(is_held), just_pressed(just_pressed), axis_active(axis_act) {}
|
: button(btn), is_held(is_held), just_pressed(just_pressed), axis_active(axis_act), trigger_active(false) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Keyboard {
|
struct Keyboard {
|
||||||
@@ -178,6 +183,7 @@ class Input {
|
|||||||
private:
|
private:
|
||||||
// --- Constantes ---
|
// --- Constantes ---
|
||||||
static constexpr Sint16 AXIS_THRESHOLD = 30000;
|
static constexpr Sint16 AXIS_THRESHOLD = 30000;
|
||||||
|
static constexpr Sint16 TRIGGER_THRESHOLD = 16384; // Umbral para triggers (aproximadamente 50% del rango)
|
||||||
static constexpr std::array<Action, 4> BUTTON_INPUTS = {Action::FIRE_LEFT, Action::FIRE_CENTER, Action::FIRE_RIGHT, Action::START}; // Listado de los inputs para jugar que utilizan botones, ni palancas ni crucetas
|
static constexpr std::array<Action, 4> BUTTON_INPUTS = {Action::FIRE_LEFT, Action::FIRE_CENTER, Action::FIRE_RIGHT, Action::START}; // Listado de los inputs para jugar que utilizan botones, ni palancas ni crucetas
|
||||||
|
|
||||||
// --- Variables internas ---
|
// --- Variables internas ---
|
||||||
@@ -190,6 +196,7 @@ class Input {
|
|||||||
// --- Métodos internos ---
|
// --- Métodos internos ---
|
||||||
void initSDLGamePad();
|
void initSDLGamePad();
|
||||||
static auto checkAxisInput(Action action, std::shared_ptr<Gamepad> gamepad, bool repeat) -> bool;
|
static auto checkAxisInput(Action action, std::shared_ptr<Gamepad> gamepad, bool repeat) -> bool;
|
||||||
|
static auto checkTriggerInput(Action action, std::shared_ptr<Gamepad> gamepad, bool repeat) -> bool;
|
||||||
auto addGamepad(int device_index) -> std::string;
|
auto addGamepad(int device_index) -> std::string;
|
||||||
auto removeGamepad(SDL_JoystickID id) -> std::string;
|
auto removeGamepad(SDL_JoystickID id) -> std::string;
|
||||||
void addGamepadMappingsFromFile();
|
void addGamepadMappingsFromFile();
|
||||||
|
|||||||
78
test_triggers.cpp
Normal file
78
test_triggers.cpp
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#include <SDL3/SDL.h>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
// Inicializar SDL
|
||||||
|
if (!SDL_Init(SDL_INIT_GAMEPAD)) {
|
||||||
|
std::cerr << "Error inicializando SDL: " << SDL_GetError() << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "Prueba de triggers L2/R2 como botones digitales" << std::endl;
|
||||||
|
std::cout << "Conecta un mando arcade y presiona L2 o R2" << std::endl;
|
||||||
|
std::cout << "Presiona ESC para salir" << std::endl;
|
||||||
|
|
||||||
|
// Abrir primer gamepad disponible
|
||||||
|
SDL_Gamepad* gamepad = nullptr;
|
||||||
|
SDL_JoystickID* joysticks = SDL_GetJoysticks(nullptr);
|
||||||
|
|
||||||
|
if (joysticks) {
|
||||||
|
for (int i = 0; joysticks[i]; i++) {
|
||||||
|
if (SDL_IsGamepad(joysticks[i])) {
|
||||||
|
gamepad = SDL_OpenGamepad(joysticks[i]);
|
||||||
|
if (gamepad) {
|
||||||
|
std::cout << "Gamepad conectado: " << SDL_GetGamepadName(gamepad) << std::endl;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SDL_free(joysticks);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!gamepad) {
|
||||||
|
std::cout << "No se encontró ningún gamepad compatible" << std::endl;
|
||||||
|
SDL_Quit();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool running = true;
|
||||||
|
SDL_Event event;
|
||||||
|
|
||||||
|
while (running) {
|
||||||
|
while (SDL_PollEvent(&event)) {
|
||||||
|
switch (event.type) {
|
||||||
|
case SDL_EVENT_QUIT:
|
||||||
|
running = false;
|
||||||
|
break;
|
||||||
|
case SDL_EVENT_GAMEPAD_AXIS_MOTION:
|
||||||
|
if (event.gaxis.axis == SDL_GAMEPAD_AXIS_LEFT_TRIGGER) {
|
||||||
|
if (event.gaxis.value > 16384) {
|
||||||
|
std::cout << "L2 PRESIONADO como botón digital (valor: " << event.gaxis.value << ")" << std::endl;
|
||||||
|
}
|
||||||
|
} else if (event.gaxis.axis == SDL_GAMEPAD_AXIS_RIGHT_TRIGGER) {
|
||||||
|
if (event.gaxis.value > 16384) {
|
||||||
|
std::cout << "R2 PRESIONADO como botón digital (valor: " << event.gaxis.value << ")" << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SDL_EVENT_GAMEPAD_BUTTON_DOWN:
|
||||||
|
std::cout << "Botón presionado: " << event.gbutton.button << std::endl;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verificar ESC para salir
|
||||||
|
const bool* keyboard_state = SDL_GetKeyboardState(nullptr);
|
||||||
|
if (keyboard_state[SDL_SCANCODE_ESCAPE]) {
|
||||||
|
running = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_Delay(16); // ~60 FPS
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gamepad) {
|
||||||
|
SDL_CloseGamepad(gamepad);
|
||||||
|
}
|
||||||
|
SDL_Quit();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user