SDL cache + output stream

This commit is contained in:
patchzyy committed 2026-08-26 22:50:20 +02:00
1 parent 21b57f08a4
commit dbf6d05625
2 files changed
+48 -12

No files matched your search

+37 -10
View File
@@ -255,6 +255,18 @@ IdentityMatch identity_match(const ControllerIdentity& saved, const ControllerId
: IdentityMatch::None; : IdentityMatch::None;
} }
void assign_player_index(GameController& controller, int32_t port) {
SDL_SetGamepadPlayerIndex(controller.m_controller, port);
controller.m_playerIndex = port;
}
// SDL forgets the index for devices mapped after connect, so player_index() falls
// back to the cached copy; both have to move together or a port looks doubly taken.
int32_t effective_player_index(const GameController& controller) {
const int32_t player = SDL_GetGamepadPlayerIndex(controller.m_controller);
return player >= 0 ? player : controller.m_playerIndex;
}
bool is_instance_claimed(const std::array<Uint32, PAD_MAX_CONTROLLERS>& claimedControllers, size_t claimedCount, bool is_instance_claimed(const std::array<Uint32, PAD_MAX_CONTROLLERS>& claimedControllers, size_t claimedCount,
Uint32 instance) { Uint32 instance) {
return std::find(claimedControllers.begin(), claimedControllers.begin() + claimedCount, instance) != return std::find(claimedControllers.begin(), claimedControllers.begin() + claimedCount, instance) !=
@@ -269,10 +281,10 @@ void apply_port_preferences() noexcept {
} }
for (auto& [instance, controller] : g_GameControllers) { for (auto& [instance, controller] : g_GameControllers) {
const int32_t player = SDL_GetGamepadPlayerIndex(controller.m_controller); const int32_t player = effective_player_index(controller);
if (player >= 0 && player < PAD_MAX_CONTROLLERS && g_portPreferences[player].state != PortPreferenceState::Unset) { if (player >= 0 && player < PAD_MAX_CONTROLLERS && g_portPreferences[player].state != PortPreferenceState::Unset) {
// Keep SDL's default player assignment from taking explicitly configured ports // Keep SDL's default player assignment from taking explicitly configured ports
SDL_SetGamepadPlayerIndex(controller.m_controller, -1); assign_player_index(controller, -1);
} }
} }
@@ -293,7 +305,7 @@ void apply_port_preferences() noexcept {
switch (identity_match(preference.identity, controller_identity(controller))) { switch (identity_match(preference.identity, controller_identity(controller))) {
case IdentityMatch::Exact: case IdentityMatch::Exact:
SDL_SetGamepadPlayerIndex(controller.m_controller, static_cast<int32_t>(port)); assign_player_index(controller, static_cast<int32_t>(port));
claimedControllers[claimedCount++] = instance; claimedControllers[claimedCount++] = instance;
fallbackController = nullptr; fallbackController = nullptr;
break; break;
@@ -311,7 +323,7 @@ void apply_port_preferences() noexcept {
} }
if (fallbackController != nullptr) { if (fallbackController != nullptr) {
SDL_SetGamepadPlayerIndex(fallbackController->m_controller, static_cast<int32_t>(port)); assign_player_index(*fallbackController, static_cast<int32_t>(port));
claimedControllers[claimedCount++] = fallbackInstance; claimedControllers[claimedCount++] = fallbackInstance;
} }
} }
@@ -320,20 +332,35 @@ void apply_port_preferences() noexcept {
// SDL only hands out a player index when the device already had a gamepad mapping // SDL only hands out a player index when the device already had a gamepad mapping
// at connect time, so anything mapped later (the setup wizard) stays at -1. // at connect time, so anything mapped later (the setup wizard) stays at -1.
void ensure_player_index(GameController& controller) noexcept { void ensure_player_index(GameController& controller) noexcept {
if (SDL_GetGamepadPlayerIndex(controller.m_controller) >= 0) { const int32_t player = SDL_GetGamepadPlayerIndex(controller.m_controller);
if (player >= 0) {
controller.m_playerIndex = player;
return; return;
} }
if (controller.m_playerIndex >= 0) {
return;
}
ensure_port_preferences_loaded();
const auto claim = [&](bool skipConfiguredPorts) {
for (int32_t port = 0; port < PAD_MAX_CONTROLLERS; ++port) { for (int32_t port = 0; port < PAD_MAX_CONTROLLERS; ++port) {
if (skipConfiguredPorts && g_portPreferences[port].state != PortPreferenceState::Unset) {
continue;
}
const bool taken = std::any_of(g_GameControllers.begin(), g_GameControllers.end(), [&](const auto& entry) { const bool taken = std::any_of(g_GameControllers.begin(), g_GameControllers.end(), [&](const auto& entry) {
return entry.second.m_controller != controller.m_controller && return entry.second.m_controller != controller.m_controller && effective_player_index(entry.second) == port;
SDL_GetGamepadPlayerIndex(entry.second.m_controller) == port;
}); });
if (!taken) { if (!taken) {
SDL_SetGamepadPlayerIndex(controller.m_controller, port); assign_player_index(controller, port);
controller.m_playerIndex = port; return true;
return;
} }
} }
return false;
};
// Explicitly configured ports are only used as a last resort so a hot-plugged
// controller cannot steal the port its preferred device will claim.
if (!claim(true)) {
claim(false);
}
} }
} // namespace } // namespace
+11 -2
View File
@@ -150,7 +150,7 @@ std::string BuildMappingString() {
return mapping; return mapping;
} }
void PersistMapping(const std::string& guid, const std::string& mapping) { bool PersistMapping(const std::string& guid, const std::string& mapping) {
const std::filesystem::path path = MappingDbPath(); const std::filesystem::path path = MappingDbPath();
std::vector<std::string> lines; std::vector<std::string> lines;
{ {
@@ -166,9 +166,14 @@ void PersistMapping(const std::string& guid, const std::string& mapping) {
std::error_code ec; std::error_code ec;
std::filesystem::create_directories(path.parent_path(), ec); std::filesystem::create_directories(path.parent_path(), ec);
std::ofstream out(path, std::ios::trunc); std::ofstream out(path, std::ios::trunc);
if (!out) {
return false;
}
for (const auto& line : lines) { for (const auto& line : lines) {
out << line << '\n'; out << line << '\n';
} }
out.close();
return static_cast<bool>(out);
} }
void FinishWizard() { void FinishWizard() {
@@ -180,7 +185,11 @@ void FinishWizard() {
<< std::endl; << std::endl;
return; return;
} }
PersistMapping(guid, mapping); if (!PersistMapping(guid, mapping)) {
g_wizard.status = "Failed to save mapping to " + MappingDbPath().string();
RT_LOG(RT_TAG_CONFIG) << "controller wizard: " << g_wizard.status << std::endl;
return;
}
RT_LOG(RT_TAG_CONFIG) << "controller wizard: applied mapping " << mapping << std::endl; RT_LOG(RT_TAG_CONFIG) << "controller wizard: applied mapping " << mapping << std::endl;
StopWizard(); StopWizard();
} }