From b10b4381ef3e5ee3b34332f64c20fd376559c185 Mon Sep 17 00:00:00 2001 From: Gleb Mazovetskiy Date: Sat, 28 Nov 2020 21:58:13 +0000 Subject: [PATCH] Multiple controllers support (#935) --- SourceS/sdl2_to_1_2_backports.h | 1 + SourceX/DiabloUI/diabloui.cpp | 5 +- SourceX/controls/controller.cpp | 48 +++++-- SourceX/controls/controller.h | 4 +- SourceX/controls/controller_motion.cpp | 6 +- SourceX/controls/devices/game_controller.cpp | 107 ++++++++++---- SourceX/controls/devices/game_controller.h | 32 ++++- SourceX/controls/devices/joystick.cpp | 138 ++++++++++++------- SourceX/controls/devices/joystick.h | 45 ++++-- SourceX/controls/game_controls.cpp | 7 +- SourceX/display.cpp | 12 +- SourceX/miniwin/misc_msg.cpp | 12 +- 12 files changed, 288 insertions(+), 129 deletions(-) diff --git a/SourceS/sdl2_to_1_2_backports.h b/SourceS/sdl2_to_1_2_backports.h index 44647810d..6124577b2 100644 --- a/SourceS/sdl2_to_1_2_backports.h +++ b/SourceS/sdl2_to_1_2_backports.h @@ -48,6 +48,7 @@ // For now we only process ASCII input when using SDL1. #define SDL_TEXTINPUTEVENT_TEXT_SIZE 2 +#define SDL_JoystickID Sint32 #define SDL_JoystickNameForIndex SDL_JoystickName inline void SDL_Log(const char *fmt, ...) diff --git a/SourceX/DiabloUI/diabloui.cpp b/SourceX/DiabloUI/diabloui.cpp index 475b7d037..a1164fff7 100644 --- a/SourceX/DiabloUI/diabloui.cpp +++ b/SourceX/DiabloUI/diabloui.cpp @@ -357,10 +357,7 @@ void UiHandleEvents(SDL_Event *event) diablo_quit(0); #ifndef USE_SDL1 - if (event->type == SDL_JOYDEVICEADDED || event->type == SDL_JOYDEVICEREMOVED) { - InitController(); - return; - } + HandleControllerAddedOrRemovedEvent(*event); if (event->type == SDL_WINDOWEVENT) { if (event->window.event == SDL_WINDOWEVENT_SHOWN) diff --git a/SourceX/controls/controller.cpp b/SourceX/controls/controller.cpp index 9834255ee..50cb2afed 100644 --- a/SourceX/controls/controller.cpp +++ b/SourceX/controls/controller.cpp @@ -8,7 +8,7 @@ namespace dvl { ControllerButtonEvent ToControllerButtonEvent(const SDL_Event &event) { - ControllerButtonEvent result{ ControllerButton_NONE, false }; + ControllerButtonEvent result { ControllerButton_NONE, false }; switch (event.type) { #ifndef USE_SDL1 case SDL_CONTROLLERBUTTONUP: @@ -28,34 +28,56 @@ ControllerButtonEvent ToControllerButtonEvent(const SDL_Event &event) #endif #ifndef USE_SDL1 - result.button = GameControllerToControllerButton(event); - if (result.button != ControllerButton_NONE) - return result; + GameController *const controller = GameController::Get(event); + if (controller != NULL) { + result.button = controller->ToControllerButton(event); + if (result.button != ControllerButton_NONE) + return result; + } #endif - result.button = JoyButtonToControllerButton(event); + const Joystick *joystick = Joystick::Get(event); + if (joystick != NULL) + result.button = joystick->ToControllerButton(event); return result; } bool IsControllerButtonPressed(ControllerButton button) { - bool result = false; #ifndef USE_SDL1 - result = result || IsGameControllerButtonPressed(button); + if (GameController::IsPressedOnAnyController(button)) + return true; #endif #if HAS_KBCTRL == 1 - result = result || IsKbCtrlButtonPressed(button); + if (IsKbCtrlButtonPressed(button)) + return true; #endif - result = result || IsJoystickButtonPressed(button); - return result; + return Joystick::IsPressedOnAnyJoystick(button); } -void InitController() +bool HandleControllerAddedOrRemovedEvent(const SDL_Event &event) { - InitJoystick(); #ifndef USE_SDL1 - InitGameController(); + 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 } diff --git a/SourceX/controls/controller.h b/SourceX/controls/controller.h index 87b45b476..7b62f6aab 100644 --- a/SourceX/controls/controller.h +++ b/SourceX/controls/controller.h @@ -1,5 +1,7 @@ #pragma once +#include + #include "controls/controller_buttons.h" namespace dvl { @@ -15,6 +17,6 @@ ControllerButtonEvent ToControllerButtonEvent(const SDL_Event &event); bool IsControllerButtonPressed(ControllerButton button); -void InitController(); +bool HandleControllerAddedOrRemovedEvent(const SDL_Event &event); } // namespace dvl diff --git a/SourceX/controls/controller_motion.cpp b/SourceX/controls/controller_motion.cpp index f6d7c28d1..b800e47b7 100644 --- a/SourceX/controls/controller_motion.cpp +++ b/SourceX/controls/controller_motion.cpp @@ -123,12 +123,14 @@ void ScaleJoysticks() bool ProcessControllerMotion(const SDL_Event &event, ControllerButtonEvent ctrl_event) { #ifndef USE_SDL1 - if (ProcessGameControllerAxisMotion(event)) { + GameController *const controller = GameController::Get(event); + if (controller != NULL && controller->ProcessAxisMotion(event)) { ScaleJoysticks(); return true; } #endif - if (ProcessJoystickAxisMotion(event)) { + Joystick *const joystick = Joystick::Get(event); + if (joystick != NULL && joystick->ProcessAxisMotion(event)) { ScaleJoysticks(); return true; } diff --git a/SourceX/controls/devices/game_controller.cpp b/SourceX/controls/devices/game_controller.cpp index 07073a4d7..7822db172 100644 --- a/SourceX/controls/devices/game_controller.cpp +++ b/SourceX/controls/devices/game_controller.cpp @@ -1,36 +1,37 @@ #include "controls/devices/game_controller.h" #ifndef USE_SDL1 + +#include + #include "controls/controller_motion.h" #include "controls/devices/joystick.h" #include "stubs.h" namespace dvl { -static SDL_GameController *current_game_controller = NULL; -static bool sgbTriggerLeftDown = false; -static bool sgbTriggerRightDown = false; +std::vector *const GameController::controllers_ = new std::vector; -ControllerButton GameControllerToControllerButton(const SDL_Event &event) +ControllerButton GameController::ToControllerButton(const SDL_Event &event) { switch (event.type) { case SDL_CONTROLLERAXISMOTION: switch (event.caxis.axis) { case SDL_CONTROLLER_AXIS_TRIGGERLEFT: if (event.caxis.value < 8192) { // 25% pressed - sgbTriggerLeftDown = false; + trigger_left_is_down_ = false; } - if (event.caxis.value > 16384 && !sgbTriggerLeftDown) { // 50% pressed - sgbTriggerLeftDown = true; + if (event.caxis.value > 16384 && !trigger_left_is_down_) { // 50% pressed + trigger_left_is_down_ = true; return ControllerButton_AXIS_TRIGGERLEFT; } return ControllerButton_NONE; case SDL_CONTROLLER_AXIS_TRIGGERRIGHT: if (event.caxis.value < 8192) { // 25% pressed - sgbTriggerRightDown = false; + trigger_right_is_down_ = false; } - if (event.caxis.value > 16384 && !sgbTriggerRightDown) { // 50% pressed - sgbTriggerRightDown = true; + if (event.caxis.value > 16384 && !trigger_right_is_down_) { // 50% pressed + trigger_right_is_down_ = true; return ControllerButton_AXIS_TRIGGERRIGHT; } return ControllerButton_NONE; @@ -76,9 +77,7 @@ ControllerButton GameControllerToControllerButton(const SDL_Event &event) return ControllerButton_NONE; } -namespace { - -SDL_GameControllerButton ControllerButtonToGameControllerButton(ControllerButton button) +SDL_GameControllerButton GameController::ToSdlGameControllerButton(ControllerButton button) const { if (button == ControllerButton_AXIS_TRIGGERLEFT || button == ControllerButton_AXIS_TRIGGERRIGHT) UNIMPLEMENTED(); @@ -116,17 +115,13 @@ SDL_GameControllerButton ControllerButtonToGameControllerButton(ControllerButton } } -} // namespace - -bool IsGameControllerButtonPressed(ControllerButton button) +bool GameController::IsPressed(ControllerButton button) const { - if (current_game_controller == NULL) - return false; - const SDL_GameControllerButton gc_button = ControllerButtonToGameControllerButton(button); - return gc_button != SDL_CONTROLLER_BUTTON_INVALID && SDL_GameControllerGetButton(current_game_controller, gc_button); + const SDL_GameControllerButton gc_button = ToSdlGameControllerButton(button); + return gc_button != SDL_CONTROLLER_BUTTON_INVALID && SDL_GameControllerGetButton(sdl_game_controller_, gc_button); } -bool ProcessGameControllerAxisMotion(const SDL_Event &event) +bool GameController::ProcessAxisMotion(const SDL_Event &event) { if (event.type != SDL_CONTROLLERAXISMOTION) return false; @@ -153,20 +148,72 @@ bool ProcessGameControllerAxisMotion(const SDL_Event &event) return true; } -SDL_GameController *CurrentGameController() +void GameController::Add(int joystick_index) { - return current_game_controller; + SDL_Log("Opening game controller for joystick at index %d", joystick_index); + GameController result; + result.sdl_game_controller_ = SDL_GameControllerOpen(joystick_index); + if (result.sdl_game_controller_ == NULL) { + SDL_Log(SDL_GetError()); + SDL_ClearError(); + return; + } + SDL_Joystick *const sdl_joystick = SDL_GameControllerGetJoystick(result.sdl_game_controller_); + result.instance_id_ = SDL_JoystickInstanceID(sdl_joystick); + controllers_->push_back(result); + + const SDL_JoystickGUID guid = SDL_JoystickGetGUID(sdl_joystick); + SDL_Log("Opened game controller with mapping:\n%s", SDL_GameControllerMappingForGUID(guid)); } -void InitGameController() +void GameController::Remove(SDL_JoystickID instance_id) { - if (CurrentJoystickIndex() == -1) + SDL_Log("Removing game controller with instance id %d", instance_id); + for (std::size_t i = 0; i < controllers_->size(); ++i) { + const GameController &controller = (*controllers_)[i]; + if (controller.instance_id_ != instance_id) + continue; + controllers_->erase(controllers_->begin() + i); + sgbControllerActive = !controllers_->empty(); return; - const SDL_JoystickGUID guid = SDL_JoystickGetGUID(CurrentJoystick()); - SDL_Log("Opening gamepad %d: %s", CurrentJoystickIndex(), SDL_GameControllerMappingForGUID(guid)); - current_game_controller = SDL_GameControllerOpen(CurrentJoystickIndex()); - if (current_game_controller == NULL) - SDL_Log(SDL_GetError()); + } + SDL_Log("Game controller not found with instance id: %d", instance_id); +} + +GameController *GameController::Get(SDL_JoystickID instance_id) +{ + for (std::size_t i = 0; i < controllers_->size(); ++i) { + GameController &controller = (*controllers_)[i]; + if (controller.instance_id_ == instance_id) + return &controller; + } + return NULL; +} + +GameController *GameController::Get(const SDL_Event &event) +{ + switch (event.type) { + case SDL_CONTROLLERAXISMOTION: + return Get(event.caxis.which); + case SDL_CONTROLLERBUTTONDOWN: + case SDL_CONTROLLERBUTTONUP: + return Get(event.jball.which); + default: + return NULL; + } +} + +const std::vector &GameController::All() +{ + return *controllers_; +} + +bool GameController::IsPressedOnAnyController(ControllerButton button) +{ + for (std::size_t i = 0; i < controllers_->size(); ++i) + if ((*controllers_)[i].IsPressed(button)) + return true; + return false; } } // namespace dvl diff --git a/SourceX/controls/devices/game_controller.h b/SourceX/controls/devices/game_controller.h index 864ebc9c5..e41e7b5e9 100644 --- a/SourceX/controls/devices/game_controller.h +++ b/SourceX/controls/devices/game_controller.h @@ -1,22 +1,42 @@ #pragma once +#include + #include + #include "controls/controller_buttons.h" #ifndef USE_SDL1 namespace dvl { -ControllerButton GameControllerToControllerButton(const SDL_Event &event); +class GameController { + static std::vector *const controllers_; + +public: + static void Add(int joystick_index); + static void Remove(SDL_JoystickID instance_id); + static GameController *Get(SDL_JoystickID instance_id); + static GameController *Get(const SDL_Event &event); + static const std::vector &All(); + static bool IsPressedOnAnyController(ControllerButton button); + + // NOTE: Not idempotent. + // Must be called exactly once for each SDL input event. + ControllerButton ToControllerButton(const SDL_Event &event); -bool IsGameControllerButtonPressed(ControllerButton button); + bool IsPressed(ControllerButton button) const; + bool ProcessAxisMotion(const SDL_Event &event); -bool ProcessGameControllerAxisMotion(const SDL_Event &event); +private: + SDL_GameControllerButton ToSdlGameControllerButton(ControllerButton button) const; -SDL_GameController *CurrentGameController(); + SDL_GameController *sdl_game_controller_ = NULL; + SDL_JoystickID instance_id_ = -1; -// Must be called after InitJoystick(). -void InitGameController(); + bool trigger_left_is_down_ = false; + bool trigger_right_is_down_ = false; +}; } // namespace dvl #endif diff --git a/SourceX/controls/devices/joystick.cpp b/SourceX/controls/devices/joystick.cpp index 1ba2a3f72..f1bebf948 100644 --- a/SourceX/controls/devices/joystick.cpp +++ b/SourceX/controls/devices/joystick.cpp @@ -1,12 +1,16 @@ #include "controls/devices/joystick.h" +#include + #include "controls/controller_motion.h" #include "stubs.h" namespace dvl { -ControllerButton JoyButtonToControllerButton(const SDL_Event &event) +std::vector *const Joystick::joysticks_ = new std::vector; + +ControllerButton Joystick::ToControllerButton(const SDL_Event &event) const { switch (event.type) { case SDL_JOYBUTTONDOWN: @@ -105,9 +109,7 @@ ControllerButton JoyButtonToControllerButton(const SDL_Event &event) return ControllerButton_NONE; } -namespace { - -int JoyButtonToControllerButton(ControllerButton button) +int Joystick::ToSdlJoyButton(ControllerButton button) const { if (button == ControllerButton_AXIS_TRIGGERLEFT || button == ControllerButton_AXIS_TRIGGERRIGHT) UNIMPLEMENTED(); @@ -173,43 +175,41 @@ int JoyButtonToControllerButton(ControllerButton button) } } -bool IsJoystickHatButtonPressed(ControllerButton button) +bool Joystick::IsHatButtonPressed(ControllerButton button) const { switch (button) { #if defined(JOY_HAT_DPAD_UP_HAT) && defined(JOY_HAT_DPAD_UP) case ControllerButton_BUTTON_DPAD_UP: - return (SDL_JoystickGetHat(CurrentJoystick(), JOY_HAT_DPAD_UP_HAT) & JOY_HAT_DPAD_UP) != 0; + return (SDL_JoystickGetHat(sdl_joystick_, JOY_HAT_DPAD_UP_HAT) & JOY_HAT_DPAD_UP) != 0; #endif #if defined(JOY_HAT_DPAD_DOWN_HAT) && defined(JOY_HAT_DPAD_DOWN) case ControllerButton_BUTTON_DPAD_DOWN: - return (SDL_JoystickGetHat(CurrentJoystick(), JOY_HAT_DPAD_DOWN_HAT) & JOY_HAT_DPAD_DOWN) != 0; + return (SDL_JoystickGetHat(sdl_joystick_, JOY_HAT_DPAD_DOWN_HAT) & JOY_HAT_DPAD_DOWN) != 0; #endif #if defined(JOY_HAT_DPAD_LEFT_HAT) && defined(JOY_HAT_DPAD_LEFT) case ControllerButton_BUTTON_DPAD_LEFT: - return (SDL_JoystickGetHat(CurrentJoystick(), JOY_HAT_DPAD_LEFT_HAT) & JOY_HAT_DPAD_LEFT) != 0; + return (SDL_JoystickGetHat(sdl_joystick_, JOY_HAT_DPAD_LEFT_HAT) & JOY_HAT_DPAD_LEFT) != 0; #endif #if defined(JOY_HAT_DPAD_RIGHT_HAT) && defined(JOY_HAT_DPAD_RIGHT) case ControllerButton_BUTTON_DPAD_RIGHT: - return (SDL_JoystickGetHat(CurrentJoystick(), JOY_HAT_DPAD_RIGHT_HAT) & JOY_HAT_DPAD_RIGHT) != 0; + return (SDL_JoystickGetHat(sdl_joystick_, JOY_HAT_DPAD_RIGHT_HAT) & JOY_HAT_DPAD_RIGHT) != 0; #endif default: return false; } } -} // namespace - -bool IsJoystickButtonPressed(ControllerButton button) +bool Joystick::IsPressed(ControllerButton button) const { - if (CurrentJoystick() == NULL) + if (sdl_joystick_ == NULL) return false; - if (IsJoystickHatButtonPressed(button)) + if (IsHatButtonPressed(button)) return true; - const int joy_button = JoyButtonToControllerButton(button); - return joy_button != -1 && SDL_JoystickGetButton(CurrentJoystick(), joy_button); + const int joy_button = ToSdlJoyButton(button); + return joy_button != -1 && SDL_JoystickGetButton(sdl_joystick_, joy_button); } -bool ProcessJoystickAxisMotion(const SDL_Event &event) +bool Joystick::ProcessAxisMotion(const SDL_Event &event) { if (event.type != SDL_JOYAXISMOTION) return false; @@ -244,50 +244,92 @@ bool ProcessJoystickAxisMotion(const SDL_Event &event) return true; } -static SDL_Joystick *current_joystick = NULL; - -SDL_Joystick *CurrentJoystick() +void Joystick::Add(int device_index) { - return current_joystick; + if (SDL_NumJoysticks() <= device_index) + return; + Joystick result; + SDL_Log("Adding joystick %d: %s", device_index, + SDL_JoystickNameForIndex(device_index)); + result.sdl_joystick_ = SDL_JoystickOpen(device_index); + if (result.sdl_joystick_ == NULL) { + SDL_Log(SDL_GetError()); + SDL_ClearError(); + return; + } +#ifndef USE_SDL1 + result.instance_id_ = SDL_JoystickInstanceID(result.sdl_joystick_); +#endif + joysticks_->push_back(result); + sgbControllerActive = true; } -static int current_joystick_index = -1; - -int CurrentJoystickIndex() +void Joystick::Remove(SDL_JoystickID instance_id) { - return current_joystick_index; +#ifndef USE_SDL1 + SDL_Log("Removing joystick (instance id: %d)", instance_id); + for (std::size_t i = 0; i < joysticks_->size(); ++i) { + const Joystick &joystick = (*joysticks_)[i]; + if (joystick.instance_id_ != instance_id) + continue; + joysticks_->erase(joysticks_->begin() + i); + sgbControllerActive = !joysticks_->empty(); + return; + } + SDL_Log("Joystick not found with instance id: %d", instance_id); +#endif } -void InitJoystick() +const std::vector &Joystick::All() { -#if HAS_KBCTRL == 1 - sgbControllerActive = true; -#endif + return *joysticks_; +} - if (SDL_NumJoysticks() == 0) { - current_joystick_index = -1; -#if HAS_KBCTRL == 0 - sgbControllerActive = false; -#endif - return; +Joystick *Joystick::Get(SDL_JoystickID instance_id) +{ + for (std::size_t i = 0; i < joysticks_->size(); ++i) { + Joystick &joystick = (*joysticks_)[i]; + if (joystick.instance_id_ == instance_id) + return &joystick; } + return NULL; +} - // Get the first available controller. - for (int i = 0; i < SDL_NumJoysticks(); ++i) { +Joystick *Joystick::Get(const SDL_Event &event) +{ + switch (event.type) { #ifndef USE_SDL1 - if (!SDL_IsGameController(i)) - continue; + case SDL_JOYAXISMOTION: + return Get(event.jaxis.which); + case SDL_JOYBALLMOTION: + return Get(event.jball.which); + case SDL_JOYHATMOTION: + return Get(event.jhat.which); + case SDL_JOYBUTTONDOWN: + case SDL_JOYBUTTONUP: + return Get(event.jbutton.which); + return Get(event.jbutton.which); + default: + return NULL; +#else + case SDL_JOYAXISMOTION: + case SDL_JOYBALLMOTION: + case SDL_JOYHATMOTION: + case SDL_JOYBUTTONDOWN: + case SDL_JOYBUTTONUP: + return joysticks_->empty() ? NULL : &(*joysticks_)[0]; + default: + return NULL; #endif - SDL_Log("Initializing joystick %d: %s", i, SDL_JoystickNameForIndex(i)); - current_joystick = SDL_JoystickOpen(i); - if (current_joystick == NULL) { - SDL_Log(SDL_GetError()); - continue; - } - current_joystick_index = i; - sgbControllerActive = true; - break; } } +bool Joystick::IsPressedOnAnyJoystick(ControllerButton button) +{ + for (std::size_t i = 0; i < joysticks_->size(); ++i) + if ((*joysticks_)[i].IsPressed(button)) + return true; + return false; +} + } // namespace dvl diff --git a/SourceX/controls/devices/joystick.h b/SourceX/controls/devices/joystick.h index 14806a57f..7b849720f 100644 --- a/SourceX/controls/devices/joystick.h +++ b/SourceX/controls/devices/joystick.h @@ -1,21 +1,44 @@ #pragma once - // Joystick mappings for SDL1 and additional buttons on SDL2. -#include -#include "controls/controller_buttons.h" - -namespace dvl { +#include -ControllerButton JoyButtonToControllerButton(const SDL_Event &event); +#include -bool IsJoystickButtonPressed(ControllerButton button); +#ifdef USE_SDL1 +#include "sdl2_to_1_2_backports.h" +#endif -bool ProcessJoystickAxisMotion(const SDL_Event &event); +#include "controls/controller_buttons.h" -SDL_Joystick *CurrentJoystick(); -int CurrentJoystickIndex(); +namespace dvl { -void InitJoystick(); +class Joystick { + static std::vector *const joysticks_; + +public: + static void Add(int device_index); + static void Remove(SDL_JoystickID instance_id); + static Joystick *Get(SDL_JoystickID instance_id); + static Joystick *Get(const SDL_Event &event); + static const std::vector &All(); + static bool IsPressedOnAnyJoystick(ControllerButton button); + + ControllerButton ToControllerButton(const SDL_Event &event) const; + bool IsPressed(ControllerButton button) const; + bool ProcessAxisMotion(const SDL_Event &event); + + SDL_JoystickID instance_id() const + { + return instance_id_; + } + +private: + int ToSdlJoyButton(ControllerButton button) const; + bool IsHatButtonPressed(ControllerButton button) const; + + SDL_Joystick *sdl_joystick_ = NULL; + SDL_JoystickID instance_id_ = -1; +}; } // namespace dvl diff --git a/SourceX/controls/game_controls.cpp b/SourceX/controls/game_controls.cpp index 551df2fb0..c077b11db 100644 --- a/SourceX/controls/game_controls.cpp +++ b/SourceX/controls/game_controls.cpp @@ -272,9 +272,10 @@ bool GetGameAction(const SDL_Event &event, ControllerButtonEvent ctrl_event, Gam } #ifndef USE_SDL1 - // Ignore unhandled joystick events if gamepad is active. - // We receive the same events as gamepad events. - if (CurrentGameController() != NULL && event.type >= SDL_JOYAXISMOTION && event.type <= SDL_JOYBUTTONUP) { + // Ignore unhandled joystick events where a GameController is open for this joystick. + // This is because SDL sends both game controller and joystick events in this case. + const Joystick *const joystick = Joystick::Get(event); + if (joystick != NULL && GameController::Get(joystick->instance_id()) != NULL) { return true; } if (event.type == SDL_CONTROLLERAXISMOTION) { diff --git a/SourceX/display.cpp b/SourceX/display.cpp index 61f053316..0292036b9 100644 --- a/SourceX/display.cpp +++ b/SourceX/display.cpp @@ -1,6 +1,8 @@ #include "display.h" #include "DiabloUI/diabloui.h" #include "controls/controller.h" +#include "controls/devices/game_controller.h" +#include "controls/devices/joystick.h" #ifdef USE_SDL1 #ifndef SDL1_VIDEO_MODE_BPP @@ -121,8 +123,14 @@ bool SpawnWindow(const char *lpWindowName) #ifdef USE_SDL1 SDL_EnableUNICODE(1); #endif -#if defined(USE_SDL1) || defined(__SWITCH__) - InitController(); +#ifdef USE_SDL1 + // On SDL 1, there are no ADDED/REMOVED events. + // Always try to initialize the first joystick. + Joystick::Add(0); +#ifdef __SWITCH__ + // TODO: There is a bug in SDL2 on Switch where it does not repport controllers on startup (Jan 1, 2020) + GameController::Add(0); +#endif #endif int width = DEFAULT_WIDTH; diff --git a/SourceX/miniwin/misc_msg.cpp b/SourceX/miniwin/misc_msg.cpp index 267f28e29..cf9c9c87e 100644 --- a/SourceX/miniwin/misc_msg.cpp +++ b/SourceX/miniwin/misc_msg.cpp @@ -337,6 +337,9 @@ bool PeekMessage(LPMSG lpMsg) return true; } + if (HandleControllerAddedOrRemovedEvent(e)) + return true; + const ControllerButtonEvent ctrl_event = ToControllerButtonEvent(e); if (ProcessControllerMotion(e, ctrl_event)) return true; @@ -448,15 +451,6 @@ bool PeekMessage(LPMSG lpMsg) } switch (e.type) { -#ifndef USE_SDL1 - case SDL_CONTROLLERDEVICEADDED: - case SDL_CONTROLLERDEVICEREMOVED: - break; - case SDL_JOYDEVICEADDED: - case SDL_JOYDEVICEREMOVED: - InitController(); - break; -#endif case SDL_QUIT: lpMsg->message = DVL_WM_QUIT; break;