input: add controller index to SDL controllers

This commit is contained in:
Megamouse 2023-06-11 13:08:07 +02:00
parent 84d2ad70e6
commit b436d2a7f4
3 changed files with 83 additions and 10 deletions

View file

@ -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)
{}
};

View file

@ -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<SDLDevice> dev = std::make_shared<SDLDevice>();
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<SDLDevice> 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<PadDevice> sdl_pad_handler::get_device(const std::string& device)
{
if (!Init() || device.empty())
@ -376,6 +431,7 @@ std::shared_ptr<PadDevice> sdl_pad_handler::get_device(const std::string& device
// Add a virtual controller until it is actually attached
std::shared_ptr<SDLDevice> dev = std::make_unique<SDLDevice>();
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<SDLDevice> 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;
}
}
}

View file

@ -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<std::string, std::shared_ptr<SDLDevice>> m_controllers;
void enumerate_devices();
std::shared_ptr<SDLDevice> get_device_by_game_controller(SDL_GameController* game_controller) const;
std::shared_ptr<PadDevice> get_device(const std::string& device) override;
PadHandlerBase::connection update_connection(const std::shared_ptr<PadDevice>& device) override;