#include "controls/controller.h" #include #ifndef USE_SDL1 #include "controls/devices/game_controller.h" #endif #include "controls/devices/joystick.h" #include "controls/devices/kbcontroller.h" #include "controls/game_controls.h" #include "controls/plrctrls.h" #include "player.h" namespace devilution { namespace { bool skipTick = false; bool heldControllerButtonEventsLocked = false; ControllerButton actionButtons[2] = { ControllerButton_ATTACK, ControllerButton_CAST_SPELL }; bool CreateActionButtonEvent(SDL_Event *event, ControllerButton button) { SDL_JoystickID which; #ifndef USE_SDL1 if (GameController::IsPressedOnAnyController(button, &which)) { event->type = SDL_CONTROLLERBUTTONDOWN; event->cbutton.button = GameController::ToSdlGameControllerButton(button); event->cbutton.state = ControllerButtonState_HELD; event->cbutton.which = which; return true; } #endif #if HAS_KBCTRL == 1 if (IsKbCtrlButtonPressed(button)) { event->type = SDL_KEYDOWN; event->key.keysym.sym = ControllerButtonToKbCtrlKeyCode(button); event->key.state = ControllerButtonState_HELD; return true; } #endif if (Joystick::IsPressedOnAnyJoystick(button)) { event->type = SDL_JOYBUTTONDOWN; event->jbutton.button = Joystick::ToSdlJoyButton(button); event->jbutton.state = ControllerButtonState_HELD; return true; } return false; } } // namespace void UnlockControllerState(const SDL_Event &event) { #ifndef USE_SDL1 GameController *const controller = GameController::Get(event); if (controller != nullptr) { controller->UnlockTriggerState(); } #endif } ControllerButtonEvent ToControllerButtonEvent(const SDL_Event &event) { ControllerButtonEvent result { ControllerButton_NONE, false, ControllerButtonState_RELEASED }; switch (event.type) { #ifndef USE_SDL1 case SDL_CONTROLLERBUTTONUP: #endif case SDL_JOYBUTTONUP: case SDL_KEYUP: result.up = true; break; default: break; } #if HAS_KBCTRL == 1 result.button = KbCtrlToControllerButton(event); result.state = event.key.state; if (result.button != ControllerButton_NONE) return result; #endif #ifndef USE_SDL1 GameController *const controller = GameController::Get(event); if (controller != nullptr) { result.button = controller->ToControllerButton(event); if (result.button != ControllerButton_NONE) { if (result.button == ControllerButton_AXIS_TRIGGERLEFT || result.button == ControllerButton_AXIS_TRIGGERRIGHT) { result.up = !controller->IsPressed(result.button); result.state = result.up ? SDL_RELEASED : SDL_PRESSED; } else { result.state = event.cbutton.state; } return result; } } #endif const Joystick *joystick = Joystick::Get(event); if (joystick != nullptr) { result.button = devilution::Joystick::ToControllerButton(event); result.state = ControllerButtonState_PRESSED; if (IsAnyOf(event.type, SDL_JOYBUTTONUP, SDL_JOYBUTTONDOWN)) result.state = event.jbutton.state; } return result; } bool IsControllerButtonPressed(ControllerButton button) { #ifndef USE_SDL1 if (GameController::IsPressedOnAnyController(button)) return true; #endif #if HAS_KBCTRL == 1 if (IsKbCtrlButtonPressed(button)) return true; #endif return Joystick::IsPressedOnAnyJoystick(button); } bool HandleControllerAddedOrRemovedEvent(const SDL_Event &event) { #ifndef USE_SDL1 switch (event.type) { case SDL_CONTROLLERDEVICEADDED: GameController::Add(event.cdevice.which); break; case SDL_CONTROLLERDEVICEREMOVED: GameController::Remove(event.cdevice.which); break; case SDL_JOYDEVICEADDED: Joystick::Add(event.jdevice.which); break; case SDL_JOYDEVICEREMOVED: Joystick::Remove(event.jdevice.which); break; default: return false; } return true; #else return false; #endif } void UnlockHeldControllerButtonEvents(const SDL_Event &event) { ControllerButtonEvent ctrlEvent = ToControllerButtonEvent(event); for (int i = 0; i < 2; ++i) if (actionButtons[i] == ctrlEvent.button) { heldControllerButtonEventsLocked = !CanControlHero(); break; } } int PollActionButtonPressed(SDL_Event *event) { if (heldControllerButtonEventsLocked) return 0; if (skipTick) { skipTick = false; return 0; } if (!Players[MyPlayerId].CanChangeAction()) return 0; for (int i = 0; i < 2; ++i) if (CreateActionButtonEvent(event, actionButtons[i])) { skipTick = true; // 1 tick is skipped for allowing the player animation to change return 1; } return 0; } } // namespace devilution