dolphin/Source/Core/InputCommon/InputProfile.cpp
2024-10-10 00:53:48 -07:00

214 lines
6.9 KiB
C++

// Copyright 2018 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "InputCommon/InputProfile.h"
#include <algorithm>
#include <iterator>
#include <fmt/format.h>
#include "Common/FileSearch.h"
#include "Common/FileUtil.h"
#include "Common/StringUtil.h"
#include "Core/ConfigManager.h"
#include "Core/Core.h"
#include "Core/HW/Wiimote.h"
#include "Core/HotkeyManager.h"
#include "InputCommon/ControllerInterface/ControllerInterface.h"
#include "InputCommon/InputConfig.h"
namespace InputProfile
{
namespace
{
constexpr int display_message_ms = 3000;
}
std::vector<std::string> GetProfilesFromSetting(const std::string& setting, const std::string& root)
{
const auto& setting_choices = SplitString(setting, ',');
std::vector<std::string> result;
for (const std::string& setting_choice : setting_choices)
{
const std::string path = root + std::string(StripWhitespace(setting_choice));
if (File::IsDirectory(path))
{
const auto files_under_directory = Common::DoFileSearch({path}, {".ini"}, true);
result.insert(result.end(), files_under_directory.begin(), files_under_directory.end());
}
else
{
const std::string file_path = path + ".ini";
if (File::Exists(file_path))
{
result.push_back(file_path);
}
}
}
return result;
}
std::vector<std::string> ProfileCycler::GetProfilesForDevice(InputConfig* device_configuration)
{
const std::string device_profile_root_location(
device_configuration->GetUserProfileDirectoryPath());
return Common::DoFileSearch({device_profile_root_location}, {".ini"}, true);
}
std::string ProfileCycler::GetProfile(CycleDirection cycle_direction, int& profile_index,
const std::vector<std::string>& profiles)
{
// update the index and bind it to the number of available strings
auto positive_modulo = [](int& i, int n) { i = (i % n + n) % n; };
profile_index += static_cast<int>(cycle_direction);
positive_modulo(profile_index, static_cast<int>(profiles.size()));
return profiles[profile_index];
}
void ProfileCycler::UpdateToProfile(const std::string& profile_filename,
ControllerEmu::EmulatedController* controller,
InputConfig* device_configuration)
{
std::string base;
SplitPath(profile_filename, nullptr, &base, nullptr);
Common::IniFile ini_file;
if (ini_file.Load(profile_filename))
{
Core::DisplayMessage("Loading input profile '" + base + "' for device '" +
controller->GetName() + "'",
display_message_ms);
controller->LoadConfig(ini_file.GetOrCreateSection("Profile"));
controller->UpdateReferences(g_controller_interface);
device_configuration->GenerateControllerTextures(ini_file);
}
else
{
Core::DisplayMessage("Unable to load input profile '" + base + "' for device '" +
controller->GetName() + "'",
display_message_ms);
}
}
std::vector<std::string>
ProfileCycler::GetMatchingProfilesFromSetting(const std::string& setting,
const std::vector<std::string>& profiles,
InputConfig* device_configuration)
{
const std::string device_profile_root_location(
device_configuration->GetUserProfileDirectoryPath());
const auto& profiles_from_setting = GetProfilesFromSetting(setting, device_profile_root_location);
if (profiles_from_setting.empty())
{
return {};
}
std::vector<std::string> result;
std::ranges::set_intersection(profiles, profiles_from_setting, std::back_inserter(result));
return result;
}
void ProfileCycler::CycleProfile(CycleDirection cycle_direction, InputConfig* device_configuration,
int& profile_index, int controller_index)
{
const auto& profiles = GetProfilesForDevice(device_configuration);
if (profiles.empty())
{
Core::DisplayMessage("No input profiles found", display_message_ms);
return;
}
const std::string profile = GetProfile(cycle_direction, profile_index, profiles);
auto* controller = device_configuration->GetController(controller_index);
if (controller)
{
UpdateToProfile(profile, controller, device_configuration);
}
else
{
Core::DisplayMessage("No controller found for index: " + std::to_string(controller_index),
display_message_ms);
}
}
void ProfileCycler::CycleProfileForGame(CycleDirection cycle_direction,
InputConfig* device_configuration, int& profile_index,
const std::string& setting, int controller_index)
{
const auto& profiles = GetProfilesForDevice(device_configuration);
if (profiles.empty())
{
Core::DisplayMessage("No input profiles found", display_message_ms);
return;
}
if (setting.empty())
{
Core::DisplayMessage("No setting found for game", display_message_ms);
return;
}
const auto& profiles_for_game =
GetMatchingProfilesFromSetting(setting, profiles, device_configuration);
if (profiles_for_game.empty())
{
Core::DisplayMessage("No input profiles found for game", display_message_ms);
return;
}
const std::string profile = GetProfile(cycle_direction, profile_index, profiles_for_game);
auto* controller = device_configuration->GetController(controller_index);
if (controller)
{
UpdateToProfile(profile, controller, device_configuration);
}
else
{
Core::DisplayMessage("No controller found for index: " + std::to_string(controller_index),
display_message_ms);
}
}
std::string ProfileCycler::GetWiimoteInputProfilesForGame(int controller_index)
{
Common::IniFile game_ini = SConfig::GetInstance().LoadGameIni();
const auto* const control_section = game_ini.GetOrCreateSection("Controls");
std::string result;
control_section->Get(fmt::format("WiimoteProfile{}", controller_index + 1), &result);
return result;
}
void ProfileCycler::NextWiimoteProfile(int controller_index)
{
CycleProfile(CycleDirection::Forward, Wiimote::GetConfig(), m_wiimote_profile_index,
controller_index);
}
void ProfileCycler::PreviousWiimoteProfile(int controller_index)
{
CycleProfile(CycleDirection::Backward, Wiimote::GetConfig(), m_wiimote_profile_index,
controller_index);
}
void ProfileCycler::NextWiimoteProfileForGame(int controller_index)
{
CycleProfileForGame(CycleDirection::Forward, Wiimote::GetConfig(), m_wiimote_profile_index,
GetWiimoteInputProfilesForGame(controller_index), controller_index);
}
void ProfileCycler::PreviousWiimoteProfileForGame(int controller_index)
{
CycleProfileForGame(CycleDirection::Backward, Wiimote::GetConfig(), m_wiimote_profile_index,
GetWiimoteInputProfilesForGame(controller_index), controller_index);
}
} // namespace InputProfile