controller.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. // Copyright 2020 yuzu Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <algorithm>
  5. #include <cstring>
  6. #include "common/assert.h"
  7. #include "common/logging/log.h"
  8. #include "common/string_util.h"
  9. #include "core/core.h"
  10. #include "core/frontend/applets/controller.h"
  11. #include "core/hle/result.h"
  12. #include "core/hle/service/am/am.h"
  13. #include "core/hle/service/am/applets/controller.h"
  14. #include "core/hle/service/hid/controllers/npad.h"
  15. namespace Service::AM::Applets {
  16. // This error code (0x183ACA) is thrown when the applet fails to initialize.
  17. [[maybe_unused]] constexpr ResultCode ERR_CONTROLLER_APPLET_3101{ErrorModule::HID, 3101};
  18. // This error code (0x183CCA) is thrown when the u32 result in ControllerSupportResultInfo is 2.
  19. [[maybe_unused]] constexpr ResultCode ERR_CONTROLLER_APPLET_3102{ErrorModule::HID, 3102};
  20. static Core::Frontend::ControllerParameters ConvertToFrontendParameters(
  21. ControllerSupportArgPrivate private_arg, ControllerSupportArgHeader header, bool enable_text,
  22. std::vector<IdentificationColor> identification_colors, std::vector<ExplainText> text) {
  23. HID::Controller_NPad::NpadStyleSet npad_style_set;
  24. npad_style_set.raw = private_arg.style_set;
  25. return {
  26. .min_players = std::max(s8{1}, header.player_count_min),
  27. .max_players = header.player_count_max,
  28. .keep_controllers_connected = header.enable_take_over_connection,
  29. .enable_single_mode = header.enable_single_mode,
  30. .enable_border_color = header.enable_identification_color,
  31. .border_colors = std::move(identification_colors),
  32. .enable_explain_text = enable_text,
  33. .explain_text = std::move(text),
  34. .allow_pro_controller = npad_style_set.fullkey == 1,
  35. .allow_handheld = npad_style_set.handheld == 1,
  36. .allow_dual_joycons = npad_style_set.joycon_dual == 1,
  37. .allow_left_joycon = npad_style_set.joycon_left == 1,
  38. .allow_right_joycon = npad_style_set.joycon_right == 1,
  39. };
  40. }
  41. Controller::Controller(Core::System& system_, LibraryAppletMode applet_mode_,
  42. const Core::Frontend::ControllerApplet& frontend_)
  43. : Applet{system_, applet_mode_}, frontend{frontend_}, system{system_} {}
  44. Controller::~Controller() = default;
  45. void Controller::Initialize() {
  46. Applet::Initialize();
  47. LOG_INFO(Service_HID, "Initializing Controller Applet.");
  48. LOG_DEBUG(Service_HID,
  49. "Initializing Applet with common_args: arg_version={}, lib_version={}, "
  50. "play_startup_sound={}, size={}, system_tick={}, theme_color={}",
  51. common_args.arguments_version, common_args.library_version,
  52. common_args.play_startup_sound, common_args.size, common_args.system_tick,
  53. common_args.theme_color);
  54. controller_applet_version = ControllerAppletVersion{common_args.library_version};
  55. const auto private_arg_storage = broker.PopNormalDataToApplet();
  56. ASSERT(private_arg_storage != nullptr);
  57. const auto& private_arg = private_arg_storage->GetData();
  58. ASSERT(private_arg.size() == sizeof(ControllerSupportArgPrivate));
  59. std::memcpy(&controller_private_arg, private_arg.data(), private_arg.size());
  60. ASSERT_MSG(controller_private_arg.arg_private_size == sizeof(ControllerSupportArgPrivate),
  61. "Unknown ControllerSupportArgPrivate revision={} with size={}",
  62. controller_applet_version, controller_private_arg.arg_private_size);
  63. // Some games such as Cave Story+ set invalid values for the ControllerSupportMode.
  64. // Defer to arg_size to set the ControllerSupportMode.
  65. if (controller_private_arg.mode >= ControllerSupportMode::MaxControllerSupportMode) {
  66. switch (controller_private_arg.arg_size) {
  67. case sizeof(ControllerSupportArgOld):
  68. case sizeof(ControllerSupportArgNew):
  69. controller_private_arg.mode = ControllerSupportMode::ShowControllerSupport;
  70. break;
  71. case sizeof(ControllerUpdateFirmwareArg):
  72. controller_private_arg.mode = ControllerSupportMode::ShowControllerFirmwareUpdate;
  73. break;
  74. default:
  75. UNIMPLEMENTED_MSG("Unknown ControllerPrivateArg mode={} with arg_size={}",
  76. controller_private_arg.mode, controller_private_arg.arg_size);
  77. controller_private_arg.mode = ControllerSupportMode::ShowControllerSupport;
  78. break;
  79. }
  80. }
  81. // Some games such as Cave Story+ set invalid values for the ControllerSupportCaller.
  82. // This is always 0 (Application) except with ShowControllerFirmwareUpdateForSystem.
  83. if (controller_private_arg.caller >= ControllerSupportCaller::MaxControllerSupportCaller) {
  84. if (controller_private_arg.flag_1 &&
  85. controller_private_arg.mode == ControllerSupportMode::ShowControllerFirmwareUpdate) {
  86. controller_private_arg.caller = ControllerSupportCaller::System;
  87. } else {
  88. controller_private_arg.caller = ControllerSupportCaller::Application;
  89. }
  90. }
  91. switch (controller_private_arg.mode) {
  92. case ControllerSupportMode::ShowControllerSupport:
  93. case ControllerSupportMode::ShowControllerStrapGuide: {
  94. const auto user_arg_storage = broker.PopNormalDataToApplet();
  95. ASSERT(user_arg_storage != nullptr);
  96. const auto& user_arg = user_arg_storage->GetData();
  97. switch (controller_applet_version) {
  98. case ControllerAppletVersion::Version3:
  99. case ControllerAppletVersion::Version4:
  100. case ControllerAppletVersion::Version5:
  101. ASSERT(user_arg.size() == sizeof(ControllerSupportArgOld));
  102. std::memcpy(&controller_user_arg_old, user_arg.data(), user_arg.size());
  103. break;
  104. case ControllerAppletVersion::Version7:
  105. ASSERT(user_arg.size() == sizeof(ControllerSupportArgNew));
  106. std::memcpy(&controller_user_arg_new, user_arg.data(), user_arg.size());
  107. break;
  108. default:
  109. UNIMPLEMENTED_MSG("Unknown ControllerSupportArg revision={} with size={}",
  110. controller_applet_version, controller_private_arg.arg_size);
  111. ASSERT(user_arg.size() >= sizeof(ControllerSupportArgNew));
  112. std::memcpy(&controller_user_arg_new, user_arg.data(), sizeof(ControllerSupportArgNew));
  113. break;
  114. }
  115. break;
  116. }
  117. case ControllerSupportMode::ShowControllerFirmwareUpdate: {
  118. const auto update_arg_storage = broker.PopNormalDataToApplet();
  119. ASSERT(update_arg_storage != nullptr);
  120. const auto& update_arg = update_arg_storage->GetData();
  121. ASSERT(update_arg.size() == sizeof(ControllerUpdateFirmwareArg));
  122. std::memcpy(&controller_update_arg, update_arg.data(), update_arg.size());
  123. break;
  124. }
  125. default: {
  126. UNIMPLEMENTED_MSG("Unimplemented ControllerSupportMode={}", controller_private_arg.mode);
  127. break;
  128. }
  129. }
  130. }
  131. bool Controller::TransactionComplete() const {
  132. return complete;
  133. }
  134. ResultCode Controller::GetStatus() const {
  135. return status;
  136. }
  137. void Controller::ExecuteInteractive() {
  138. UNREACHABLE_MSG("Attempted to call interactive execution on non-interactive applet.");
  139. }
  140. void Controller::Execute() {
  141. switch (controller_private_arg.mode) {
  142. case ControllerSupportMode::ShowControllerSupport: {
  143. const auto parameters = [this] {
  144. switch (controller_applet_version) {
  145. case ControllerAppletVersion::Version3:
  146. case ControllerAppletVersion::Version4:
  147. case ControllerAppletVersion::Version5:
  148. return ConvertToFrontendParameters(
  149. controller_private_arg, controller_user_arg_old.header,
  150. controller_user_arg_old.enable_explain_text,
  151. std::vector<IdentificationColor>(
  152. controller_user_arg_old.identification_colors.begin(),
  153. controller_user_arg_old.identification_colors.end()),
  154. std::vector<ExplainText>(controller_user_arg_old.explain_text.begin(),
  155. controller_user_arg_old.explain_text.end()));
  156. case ControllerAppletVersion::Version7:
  157. default:
  158. return ConvertToFrontendParameters(
  159. controller_private_arg, controller_user_arg_new.header,
  160. controller_user_arg_new.enable_explain_text,
  161. std::vector<IdentificationColor>(
  162. controller_user_arg_new.identification_colors.begin(),
  163. controller_user_arg_new.identification_colors.end()),
  164. std::vector<ExplainText>(controller_user_arg_new.explain_text.begin(),
  165. controller_user_arg_new.explain_text.end()));
  166. }
  167. }();
  168. is_single_mode = parameters.enable_single_mode;
  169. LOG_DEBUG(Service_HID,
  170. "Controller Parameters: min_players={}, max_players={}, "
  171. "keep_controllers_connected={}, enable_single_mode={}, enable_border_color={}, "
  172. "enable_explain_text={}, allow_pro_controller={}, allow_handheld={}, "
  173. "allow_dual_joycons={}, allow_left_joycon={}, allow_right_joycon={}",
  174. parameters.min_players, parameters.max_players,
  175. parameters.keep_controllers_connected, parameters.enable_single_mode,
  176. parameters.enable_border_color, parameters.enable_explain_text,
  177. parameters.allow_pro_controller, parameters.allow_handheld,
  178. parameters.allow_dual_joycons, parameters.allow_left_joycon,
  179. parameters.allow_right_joycon);
  180. frontend.ReconfigureControllers([this] { ConfigurationComplete(); }, parameters);
  181. break;
  182. }
  183. case ControllerSupportMode::ShowControllerStrapGuide:
  184. case ControllerSupportMode::ShowControllerFirmwareUpdate:
  185. UNIMPLEMENTED_MSG("ControllerSupportMode={} is not implemented",
  186. controller_private_arg.mode);
  187. ConfigurationComplete();
  188. break;
  189. default: {
  190. ConfigurationComplete();
  191. break;
  192. }
  193. }
  194. }
  195. void Controller::ConfigurationComplete() {
  196. ControllerSupportResultInfo result_info{};
  197. const auto& players = Settings::values.players.GetValue();
  198. // If enable_single_mode is enabled, player_count is 1 regardless of any other parameters.
  199. // Otherwise, only count connected players from P1-P8.
  200. result_info.player_count =
  201. is_single_mode
  202. ? 1
  203. : static_cast<s8>(std::count_if(players.begin(), players.end() - 2,
  204. [](const auto& player) { return player.connected; }));
  205. result_info.selected_id = HID::Controller_NPad::IndexToNPad(std::distance(
  206. players.begin(), std::find_if(players.begin(), players.end(),
  207. [](const auto& player) { return player.connected; })));
  208. result_info.result = 0;
  209. LOG_DEBUG(Service_HID, "Result Info: player_count={}, selected_id={}, result={}",
  210. result_info.player_count, result_info.selected_id, result_info.result);
  211. complete = true;
  212. out_data = std::vector<u8>(sizeof(ControllerSupportResultInfo));
  213. std::memcpy(out_data.data(), &result_info, out_data.size());
  214. broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(out_data)));
  215. broker.SignalStateChanged();
  216. }
  217. } // namespace Service::AM::Applets