From b436d2a7f4f26047d2c6b4f0031209810f064821 Mon Sep 17 00:00:00 2001 From: Megamouse Date: Sun, 11 Jun 2023 13:08:07 +0200 Subject: [PATCH] input: add controller index to SDL controllers --- rpcs3/Emu/Io/PadHandler.h | 2 +- rpcs3/Input/sdl_pad_handler.cpp | 88 +++++++++++++++++++++++++++++---- rpcs3/Input/sdl_pad_handler.h | 3 ++ 3 files changed, 83 insertions(+), 10 deletions(-) diff --git a/rpcs3/Emu/Io/PadHandler.h b/rpcs3/Emu/Io/PadHandler.h index 17f4faa241..4bc7caf2e0 100644 --- a/rpcs3/Emu/Io/PadHandler.h +++ b/rpcs3/Emu/Io/PadHandler.h @@ -43,7 +43,7 @@ struct pad_list_entry bool is_buddy_only = false; explicit pad_list_entry(std::string _name, bool _is_buddy_only) - : name(_name), is_buddy_only(_is_buddy_only) + : name(std::move(_name)), is_buddy_only(_is_buddy_only) {} }; diff --git a/rpcs3/Input/sdl_pad_handler.cpp b/rpcs3/Input/sdl_pad_handler.cpp index 8f726f0dff..925eeb7f29 100644 --- a/rpcs3/Input/sdl_pad_handler.cpp +++ b/rpcs3/Input/sdl_pad_handler.cpp @@ -355,14 +355,69 @@ void sdl_pad_handler::enumerate_devices() if (SDLDevice::sdl_info info = get_sdl_info(i); info.game_controller) { - std::string name = info.name; std::shared_ptr dev = std::make_shared(); dev->sdl = std::move(info); - m_controllers[std::move(name)] = std::move(dev); + + // Count existing real devices with the same name + u32 device_count = 1; // This device also counts + for (const auto& controller : m_controllers) + { + if (controller.second && !controller.second->sdl.is_virtual_device && controller.second->sdl.name == dev->sdl.name) + { + device_count++; + } + } + + // Add real device + const std::string device_name = fmt::format("%s %d", dev->sdl.name, device_count); + m_controllers[device_name] = std::move(dev); } } } +std::shared_ptr sdl_pad_handler::get_device_by_game_controller(SDL_GameController* game_controller) const +{ + if (!game_controller) + return nullptr; + + const char* name = SDL_GameControllerName(game_controller); + const char* path = SDL_GameControllerPath(game_controller); + const char* serial = SDL_GameControllerGetSerial(game_controller); + + // Try to find a real device + for (const auto& controller : m_controllers) + { + if (!controller.second || controller.second->sdl.is_virtual_device) + continue; + + const auto is_same = [](const char* c, std::string_view s) -> bool + { + return c ? c == s : s.empty(); + }; + + if (is_same(name, controller.second->sdl.name) && + is_same(path, controller.second->sdl.path) && + is_same(serial, controller.second->sdl.serial)) + { + return controller.second; + } + } + + // Try to find a virtual device if we can't find a real device + for (const auto& controller : m_controllers) + { + if (!controller.second || !controller.second->sdl.is_virtual_device) + continue; + + if (name && controller.second->sdl.name.starts_with(name)) + { + return controller.second; + } + } + + return nullptr; +} + std::shared_ptr sdl_pad_handler::get_device(const std::string& device) { if (!Init() || device.empty()) @@ -376,6 +431,7 @@ std::shared_ptr sdl_pad_handler::get_device(const std::string& device // Add a virtual controller until it is actually attached std::shared_ptr dev = std::make_unique(); dev->sdl.name = device; + dev->sdl.is_virtual_device = true; m_controllers.emplace(device, dev); sdl_log.warning("Adding empty device: %s", device); @@ -418,16 +474,30 @@ PadHandlerBase::connection sdl_pad_handler::update_connection(const std::shared_ continue; } - if (const char* name = SDL_GameControllerNameForIndex(i)) + // Get game controller + SDL_GameController* game_controller = SDL_GameControllerOpen(i); + if (!game_controller) { - if (dev->sdl.name == name) + continue; + } + + // Find out if we already know this controller + std::shared_ptr sdl_device = get_device_by_game_controller(game_controller); + if (!sdl_device) + { + // Close the game controller if we don't know it. + SDL_GameControllerClose(game_controller); + continue; + } + + // Re-attach the controller if the device matches the current one + if (sdl_device.get() == dev) + { + if (SDLDevice::sdl_info info = get_sdl_info(i); info.game_controller) { - if (SDLDevice::sdl_info info = get_sdl_info(i); info.game_controller) - { - dev->sdl = std::move(info); - } - break; + dev->sdl = std::move(info); } + break; } } } diff --git a/rpcs3/Input/sdl_pad_handler.h b/rpcs3/Input/sdl_pad_handler.h index 7ce8c92af0..a070423b96 100644 --- a/rpcs3/Input/sdl_pad_handler.h +++ b/rpcs3/Input/sdl_pad_handler.h @@ -24,6 +24,8 @@ public: u16 product_version = 0; u16 firmware_version = 0; + bool is_virtual_device = false; + bool has_led = false; bool has_rumble = false; bool has_rumble_triggers = false; @@ -112,6 +114,7 @@ private: std::map> m_controllers; void enumerate_devices(); + std::shared_ptr get_device_by_game_controller(SDL_GameController* game_controller) const; std::shared_ptr get_device(const std::string& device) override; PadHandlerBase::connection update_connection(const std::shared_ptr& device) override;