InputConfig.cpp 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. // Copyright 2010 Dolphin Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include "InputCommon/InputConfig.h"
  4. #include <vector>
  5. #include "Common/Config/Config.h"
  6. #include "Common/FileUtil.h"
  7. #include "Common/IniFile.h"
  8. #include "Common/MsgHandler.h"
  9. #include "Common/StringUtil.h"
  10. #include "Core/ConfigManager.h"
  11. #include "Core/Core.h"
  12. #include "Core/HW/Wiimote.h"
  13. #include "InputCommon/ControllerEmu/ControlGroup/ControlGroup.h"
  14. #include "InputCommon/ControllerEmu/ControllerEmu.h"
  15. #include "InputCommon/ControllerEmu/Setting/NumericSetting.h"
  16. #include "InputCommon/ControllerInterface/ControllerInterface.h"
  17. #include "InputCommon/InputProfile.h"
  18. InputConfig::InputConfig(const std::string& ini_name, const std::string& gui_name,
  19. const std::string& profile_directory_name, const std::string& profile_key)
  20. : m_ini_name(ini_name), m_gui_name(gui_name), m_profile_directory_name(profile_directory_name),
  21. m_profile_key(profile_key)
  22. {
  23. }
  24. InputConfig::~InputConfig() = default;
  25. bool InputConfig::LoadConfig()
  26. {
  27. Common::IniFile inifile;
  28. bool useProfile[MAX_BBMOTES] = {false, false, false, false, false};
  29. static constexpr std::array<std::string_view, MAX_BBMOTES> num = {"1", "2", "3", "4", "BB"};
  30. std::string profile[MAX_BBMOTES];
  31. if (SConfig::GetInstance().GetGameID() != "00000000")
  32. {
  33. const std::string profile_directory = GetUserProfileDirectoryPath();
  34. Common::IniFile game_ini = SConfig::GetInstance().LoadGameIni();
  35. auto* control_section = game_ini.GetOrCreateSection("Controls");
  36. for (int i = 0; i < 4; i++)
  37. {
  38. const auto profile_name = fmt::format("{}Profile{}", GetProfileKey(), num[i]);
  39. if (control_section->Exists(profile_name))
  40. {
  41. std::string profile_setting;
  42. if (control_section->Get(profile_name, &profile_setting))
  43. {
  44. auto profiles = InputProfile::GetProfilesFromSetting(profile_setting, profile_directory);
  45. if (profiles.empty())
  46. {
  47. // TODO: PanicAlert shouldn't be used for this.
  48. PanicAlertFmtT("No profiles found for game setting '{0}'", profile_setting);
  49. continue;
  50. }
  51. // Use the first profile by default
  52. profile[i] = profiles[0];
  53. useProfile[i] = true;
  54. }
  55. }
  56. }
  57. }
  58. if (inifile.Load(File::GetUserPath(D_CONFIG_IDX) + m_ini_name + ".ini") &&
  59. !inifile.GetSections().empty())
  60. {
  61. int n = 0;
  62. std::vector<std::string> controller_names;
  63. for (auto& controller : m_controllers)
  64. {
  65. Common::IniFile::Section config;
  66. // Load settings from ini
  67. if (useProfile[n])
  68. {
  69. std::string base;
  70. SplitPath(profile[n], nullptr, &base, nullptr);
  71. Core::DisplayMessage("Loading game specific input profile '" + base + "' for device '" +
  72. controller->GetName() + "'",
  73. 6000);
  74. inifile.Load(profile[n]);
  75. config = *inifile.GetOrCreateSection("Profile");
  76. }
  77. else
  78. {
  79. config = *inifile.GetOrCreateSection(controller->GetName());
  80. }
  81. controller->LoadConfig(&config);
  82. controller->UpdateReferences(g_controller_interface);
  83. controller_names.push_back(controller->GetName());
  84. // Next profile
  85. n++;
  86. }
  87. return true;
  88. }
  89. else
  90. {
  91. // Only load the default profile for the first controller and clear the others,
  92. // otherwise they would all share the same mappings on the same (default) device
  93. if (m_controllers.size() > 0)
  94. {
  95. m_controllers[0]->LoadDefaults(g_controller_interface);
  96. m_controllers[0]->UpdateReferences(g_controller_interface);
  97. }
  98. for (size_t i = 1; i < m_controllers.size(); ++i)
  99. {
  100. // Calling the base version just clears all settings without overwriting them with a default
  101. m_controllers[i]->EmulatedController::LoadDefaults(g_controller_interface);
  102. m_controllers[i]->UpdateReferences(g_controller_interface);
  103. }
  104. return false;
  105. }
  106. }
  107. void InputConfig::SaveConfig()
  108. {
  109. std::string ini_filename = File::GetUserPath(D_CONFIG_IDX) + m_ini_name + ".ini";
  110. Common::IniFile inifile;
  111. inifile.Load(ini_filename);
  112. std::vector<std::string> controller_names;
  113. for (auto& controller : m_controllers)
  114. {
  115. controller->SaveConfig(inifile.GetOrCreateSection(controller->GetName()));
  116. controller_names.push_back(controller->GetName());
  117. }
  118. inifile.Save(ini_filename);
  119. }
  120. ControllerEmu::EmulatedController* InputConfig::GetController(int index) const
  121. {
  122. return m_controllers.at(index).get();
  123. }
  124. void InputConfig::ClearControllers()
  125. {
  126. m_controllers.clear();
  127. }
  128. bool InputConfig::ControllersNeedToBeCreated() const
  129. {
  130. return m_controllers.empty();
  131. }
  132. std::string InputConfig::GetUserProfileDirectoryPath() const
  133. {
  134. return fmt::format("{}Profiles/{}/", File::GetUserPath(D_CONFIG_IDX), GetProfileDirectoryName());
  135. }
  136. std::string InputConfig::GetSysProfileDirectoryPath() const
  137. {
  138. return fmt::format("{}Profiles/{}/", File::GetSysDirectory(), GetProfileDirectoryName());
  139. }
  140. int InputConfig::GetControllerCount() const
  141. {
  142. return static_cast<int>(m_controllers.size());
  143. }
  144. void InputConfig::RegisterHotplugCallback()
  145. {
  146. // Update control references on all controllers
  147. // as configured devices may have been added or removed.
  148. m_hotplug_callback_handle = g_controller_interface.RegisterDevicesChangedCallback([this] {
  149. for (auto& controller : m_controllers)
  150. controller->UpdateReferences(g_controller_interface);
  151. });
  152. }
  153. void InputConfig::UnregisterHotplugCallback()
  154. {
  155. g_controller_interface.UnregisterDevicesChangedCallback(m_hotplug_callback_handle);
  156. }
  157. bool InputConfig::IsControllerControlledByGamepadDevice(int index) const
  158. {
  159. if (static_cast<size_t>(index) >= m_controllers.size())
  160. return false;
  161. const auto& controller = m_controllers.at(index).get()->GetDefaultDevice();
  162. // By default on Android, no device is selected
  163. if (controller.source == "")
  164. return false;
  165. // Filter out anything which obviously not a gamepad
  166. return !((controller.source == "Quartz") // OSX Quartz Keyboard/Mouse
  167. || (controller.source == "XInput2") // Linux and BSD Keyboard/Mouse
  168. || (controller.source == "Android" && controller.cid <= 0) // Android non-gamepad device
  169. || (controller.source == "DInput" &&
  170. controller.name == "Keyboard Mouse")); // Windows Keyboard/Mouse
  171. }
  172. void InputConfig::GenerateControllerTextures(const Common::IniFile& file)
  173. {
  174. m_dynamic_input_tex_config_manager.Load();
  175. std::vector<std::string> controller_names;
  176. for (auto& controller : m_controllers)
  177. {
  178. controller_names.push_back(controller->GetName());
  179. }
  180. m_dynamic_input_tex_config_manager.GenerateTextures(file, controller_names);
  181. }
  182. void InputConfig::GenerateControllerTextures()
  183. {
  184. const std::string ini_filename = File::GetUserPath(D_CONFIG_IDX) + m_ini_name + ".ini";
  185. Common::IniFile inifile;
  186. inifile.Load(ini_filename);
  187. for (auto& controller : m_controllers)
  188. {
  189. controller->SaveConfig(inifile.GetOrCreateSection(controller->GetName()));
  190. }
  191. GenerateControllerTextures(inifile);
  192. }