summaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
authorGravatar Morph2020-08-21 07:39:24 -0400
committerGravatar Morph2020-09-04 12:23:25 -0400
commit5219615418920be8502aa24507572cf0930d65ea (patch)
treed15e05d0bf328d5e289409977cf07b30ca84fe7e /src/core
parentMerge pull request #4596 from FearlessTobi/port-5495 (diff)
downloadyuzu-5219615418920be8502aa24507572cf0930d65ea.tar.gz
yuzu-5219615418920be8502aa24507572cf0930d65ea.tar.xz
yuzu-5219615418920be8502aa24507572cf0930d65ea.zip
Project Mjölnir: Part 2 - Controller Applet
Co-authored-by: Its-Rei <kupfel@gmail.com>
Diffstat (limited to 'src/core')
-rw-r--r--src/core/CMakeLists.txt4
-rw-r--r--src/core/frontend/applets/controller.cpp40
-rw-r--r--src/core/frontend/applets/controller.h45
-rw-r--r--src/core/hle/service/am/applets/applets.cpp71
-rw-r--r--src/core/hle/service/am/applets/applets.h19
-rw-r--r--src/core/hle/service/am/applets/controller.cpp197
-rw-r--r--src/core/hle/service/am/applets/controller.h119
-rw-r--r--src/core/hle/service/hid/controllers/npad.cpp28
-rw-r--r--src/core/hle/service/hid/controllers/npad.h6
9 files changed, 487 insertions, 42 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index c85c9485f..a39940e4c 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -126,6 +126,8 @@ add_library(core STATIC
126 file_sys/vfs_vector.h 126 file_sys/vfs_vector.h
127 file_sys/xts_archive.cpp 127 file_sys/xts_archive.cpp
128 file_sys/xts_archive.h 128 file_sys/xts_archive.h
129 frontend/applets/controller.cpp
130 frontend/applets/controller.h
129 frontend/applets/error.cpp 131 frontend/applets/error.cpp
130 frontend/applets/error.h 132 frontend/applets/error.h
131 frontend/applets/general_frontend.cpp 133 frontend/applets/general_frontend.cpp
@@ -244,6 +246,8 @@ add_library(core STATIC
244 hle/service/am/applet_oe.h 246 hle/service/am/applet_oe.h
245 hle/service/am/applets/applets.cpp 247 hle/service/am/applets/applets.cpp
246 hle/service/am/applets/applets.h 248 hle/service/am/applets/applets.h
249 hle/service/am/applets/controller.cpp
250 hle/service/am/applets/controller.h
247 hle/service/am/applets/error.cpp 251 hle/service/am/applets/error.cpp
248 hle/service/am/applets/error.h 252 hle/service/am/applets/error.h
249 hle/service/am/applets/general_backend.cpp 253 hle/service/am/applets/general_backend.cpp
diff --git a/src/core/frontend/applets/controller.cpp b/src/core/frontend/applets/controller.cpp
new file mode 100644
index 000000000..0fbc7932c
--- /dev/null
+++ b/src/core/frontend/applets/controller.cpp
@@ -0,0 +1,40 @@
1// Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "core/core.h"
6#include "core/frontend/applets/controller.h"
7#include "core/hle/service/hid/controllers/npad.h"
8#include "core/hle/service/hid/hid.h"
9#include "core/hle/service/sm/sm.h"
10
11namespace Core::Frontend {
12
13ControllerApplet::~ControllerApplet() = default;
14
15DefaultControllerApplet::~DefaultControllerApplet() = default;
16
17void DefaultControllerApplet::ReconfigureControllers(std::function<void()> callback,
18 ControllerParameters parameters) const {
19 LOG_INFO(Service_HID, "called, deducing the best configuration based on the given parameters!");
20
21 auto& npad =
22 Core::System::GetInstance()
23 .ServiceManager()
24 .GetService<Service::HID::Hid>("hid")
25 ->GetAppletResource()
26 ->GetController<Service::HID::Controller_NPad>(Service::HID::HidController::NPad);
27
28 auto& players = Settings::values.players;
29
30 // Deduce the best configuration based on the input parameters.
31 for (std::size_t index = 0; index < players.size(); ++index) {
32 // First, disconnect all controllers regardless of the value of keep_controllers_connected.
33 // This makes it easy to connect the desired controllers.
34 npad.DisconnectNPadAtIndex(index);
35 }
36
37 callback();
38}
39
40} // namespace Core::Frontend
diff --git a/src/core/frontend/applets/controller.h b/src/core/frontend/applets/controller.h
new file mode 100644
index 000000000..0908f2b69
--- /dev/null
+++ b/src/core/frontend/applets/controller.h
@@ -0,0 +1,45 @@
1// Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <functional>
8
9#include "common/common_types.h"
10
11namespace Core::Frontend {
12
13using BorderColor = std::array<u8, 4>;
14
15struct ControllerParameters {
16 s8 min_players{};
17 s8 max_players{};
18 bool keep_controllers_connected{};
19 bool enable_single_mode{};
20 bool enable_border_color{};
21 std::vector<BorderColor> border_colors{};
22 bool allow_pro_controller{};
23 bool allow_handheld{};
24 bool allow_dual_joycons{};
25 bool allow_left_joycon{};
26 bool allow_right_joycon{};
27};
28
29class ControllerApplet {
30public:
31 virtual ~ControllerApplet();
32
33 virtual void ReconfigureControllers(std::function<void()> callback,
34 ControllerParameters parameters) const = 0;
35};
36
37class DefaultControllerApplet final : public ControllerApplet {
38public:
39 ~DefaultControllerApplet() override;
40
41 void ReconfigureControllers(std::function<void()> callback,
42 ControllerParameters parameters) const override;
43};
44
45} // namespace Core::Frontend
diff --git a/src/core/hle/service/am/applets/applets.cpp b/src/core/hle/service/am/applets/applets.cpp
index c3261f3e6..4e0800f9a 100644
--- a/src/core/hle/service/am/applets/applets.cpp
+++ b/src/core/hle/service/am/applets/applets.cpp
@@ -5,6 +5,7 @@
5#include <cstring> 5#include <cstring>
6#include "common/assert.h" 6#include "common/assert.h"
7#include "core/core.h" 7#include "core/core.h"
8#include "core/frontend/applets/controller.h"
8#include "core/frontend/applets/error.h" 9#include "core/frontend/applets/error.h"
9#include "core/frontend/applets/general_frontend.h" 10#include "core/frontend/applets/general_frontend.h"
10#include "core/frontend/applets/profile_select.h" 11#include "core/frontend/applets/profile_select.h"
@@ -15,6 +16,7 @@
15#include "core/hle/kernel/writable_event.h" 16#include "core/hle/kernel/writable_event.h"
16#include "core/hle/service/am/am.h" 17#include "core/hle/service/am/am.h"
17#include "core/hle/service/am/applets/applets.h" 18#include "core/hle/service/am/applets/applets.h"
19#include "core/hle/service/am/applets/controller.h"
18#include "core/hle/service/am/applets/error.h" 20#include "core/hle/service/am/applets/error.h"
19#include "core/hle/service/am/applets/general_backend.h" 21#include "core/hle/service/am/applets/general_backend.h"
20#include "core/hle/service/am/applets/profile_select.h" 22#include "core/hle/service/am/applets/profile_select.h"
@@ -140,14 +142,14 @@ void Applet::Initialize() {
140 142
141AppletFrontendSet::AppletFrontendSet() = default; 143AppletFrontendSet::AppletFrontendSet() = default;
142 144
143AppletFrontendSet::AppletFrontendSet(ParentalControlsApplet parental_controls, ErrorApplet error, 145AppletFrontendSet::AppletFrontendSet(ControllerApplet controller, ECommerceApplet e_commerce,
146 ErrorApplet error, ParentalControlsApplet parental_controls,
144 PhotoViewer photo_viewer, ProfileSelect profile_select, 147 PhotoViewer photo_viewer, ProfileSelect profile_select,
145 SoftwareKeyboard software_keyboard, WebBrowser web_browser, 148 SoftwareKeyboard software_keyboard, WebBrowser web_browser)
146 ECommerceApplet e_commerce) 149 : controller{std::move(controller)}, e_commerce{std::move(e_commerce)}, error{std::move(error)},
147 : parental_controls{std::move(parental_controls)}, error{std::move(error)}, 150 parental_controls{std::move(parental_controls)}, photo_viewer{std::move(photo_viewer)},
148 photo_viewer{std::move(photo_viewer)}, profile_select{std::move(profile_select)}, 151 profile_select{std::move(profile_select)}, software_keyboard{std::move(software_keyboard)},
149 software_keyboard{std::move(software_keyboard)}, web_browser{std::move(web_browser)}, 152 web_browser{std::move(web_browser)} {}
150 e_commerce{std::move(e_commerce)} {}
151 153
152AppletFrontendSet::~AppletFrontendSet() = default; 154AppletFrontendSet::~AppletFrontendSet() = default;
153 155
@@ -164,20 +166,37 @@ const AppletFrontendSet& AppletManager::GetAppletFrontendSet() const {
164} 166}
165 167
166void AppletManager::SetAppletFrontendSet(AppletFrontendSet set) { 168void AppletManager::SetAppletFrontendSet(AppletFrontendSet set) {
167 if (set.parental_controls != nullptr) 169 if (set.controller != nullptr) {
168 frontend.parental_controls = std::move(set.parental_controls); 170 frontend.controller = std::move(set.controller);
169 if (set.error != nullptr) 171 }
172
173 if (set.e_commerce != nullptr) {
174 frontend.e_commerce = std::move(set.e_commerce);
175 }
176
177 if (set.error != nullptr) {
170 frontend.error = std::move(set.error); 178 frontend.error = std::move(set.error);
171 if (set.photo_viewer != nullptr) 179 }
180
181 if (set.parental_controls != nullptr) {
182 frontend.parental_controls = std::move(set.parental_controls);
183 }
184
185 if (set.photo_viewer != nullptr) {
172 frontend.photo_viewer = std::move(set.photo_viewer); 186 frontend.photo_viewer = std::move(set.photo_viewer);
173 if (set.profile_select != nullptr) 187 }
188
189 if (set.profile_select != nullptr) {
174 frontend.profile_select = std::move(set.profile_select); 190 frontend.profile_select = std::move(set.profile_select);
175 if (set.software_keyboard != nullptr) 191 }
192
193 if (set.software_keyboard != nullptr) {
176 frontend.software_keyboard = std::move(set.software_keyboard); 194 frontend.software_keyboard = std::move(set.software_keyboard);
177 if (set.web_browser != nullptr) 195 }
196
197 if (set.web_browser != nullptr) {
178 frontend.web_browser = std::move(set.web_browser); 198 frontend.web_browser = std::move(set.web_browser);
179 if (set.e_commerce != nullptr) 199 }
180 frontend.e_commerce = std::move(set.e_commerce);
181} 200}
182 201
183void AppletManager::SetDefaultAppletFrontendSet() { 202void AppletManager::SetDefaultAppletFrontendSet() {
@@ -186,15 +205,23 @@ void AppletManager::SetDefaultAppletFrontendSet() {
186} 205}
187 206
188void AppletManager::SetDefaultAppletsIfMissing() { 207void AppletManager::SetDefaultAppletsIfMissing() {
189 if (frontend.parental_controls == nullptr) { 208 if (frontend.controller == nullptr) {
190 frontend.parental_controls = 209 frontend.controller = std::make_unique<Core::Frontend::DefaultControllerApplet>();
191 std::make_unique<Core::Frontend::DefaultParentalControlsApplet>(); 210 }
211
212 if (frontend.e_commerce == nullptr) {
213 frontend.e_commerce = std::make_unique<Core::Frontend::DefaultECommerceApplet>();
192 } 214 }
193 215
194 if (frontend.error == nullptr) { 216 if (frontend.error == nullptr) {
195 frontend.error = std::make_unique<Core::Frontend::DefaultErrorApplet>(); 217 frontend.error = std::make_unique<Core::Frontend::DefaultErrorApplet>();
196 } 218 }
197 219
220 if (frontend.parental_controls == nullptr) {
221 frontend.parental_controls =
222 std::make_unique<Core::Frontend::DefaultParentalControlsApplet>();
223 }
224
198 if (frontend.photo_viewer == nullptr) { 225 if (frontend.photo_viewer == nullptr) {
199 frontend.photo_viewer = std::make_unique<Core::Frontend::DefaultPhotoViewerApplet>(); 226 frontend.photo_viewer = std::make_unique<Core::Frontend::DefaultPhotoViewerApplet>();
200 } 227 }
@@ -211,10 +238,6 @@ void AppletManager::SetDefaultAppletsIfMissing() {
211 if (frontend.web_browser == nullptr) { 238 if (frontend.web_browser == nullptr) {
212 frontend.web_browser = std::make_unique<Core::Frontend::DefaultWebBrowserApplet>(); 239 frontend.web_browser = std::make_unique<Core::Frontend::DefaultWebBrowserApplet>();
213 } 240 }
214
215 if (frontend.e_commerce == nullptr) {
216 frontend.e_commerce = std::make_unique<Core::Frontend::DefaultECommerceApplet>();
217 }
218} 241}
219 242
220void AppletManager::ClearAll() { 243void AppletManager::ClearAll() {
@@ -225,6 +248,8 @@ std::shared_ptr<Applet> AppletManager::GetApplet(AppletId id) const {
225 switch (id) { 248 switch (id) {
226 case AppletId::Auth: 249 case AppletId::Auth:
227 return std::make_shared<Auth>(system, *frontend.parental_controls); 250 return std::make_shared<Auth>(system, *frontend.parental_controls);
251 case AppletId::Controller:
252 return std::make_shared<Controller>(system, *frontend.controller);
228 case AppletId::Error: 253 case AppletId::Error:
229 return std::make_shared<Error>(system, *frontend.error); 254 return std::make_shared<Error>(system, *frontend.error);
230 case AppletId::ProfileSelect: 255 case AppletId::ProfileSelect:
diff --git a/src/core/hle/service/am/applets/applets.h b/src/core/hle/service/am/applets/applets.h
index e75be86a2..a1f4cf897 100644
--- a/src/core/hle/service/am/applets/applets.h
+++ b/src/core/hle/service/am/applets/applets.h
@@ -17,6 +17,7 @@ class System;
17} 17}
18 18
19namespace Core::Frontend { 19namespace Core::Frontend {
20class ControllerApplet;
20class ECommerceApplet; 21class ECommerceApplet;
21class ErrorApplet; 22class ErrorApplet;
22class ParentalControlsApplet; 23class ParentalControlsApplet;
@@ -155,19 +156,20 @@ protected:
155}; 156};
156 157
157struct AppletFrontendSet { 158struct AppletFrontendSet {
158 using ParentalControlsApplet = std::unique_ptr<Core::Frontend::ParentalControlsApplet>; 159 using ControllerApplet = std::unique_ptr<Core::Frontend::ControllerApplet>;
160 using ECommerceApplet = std::unique_ptr<Core::Frontend::ECommerceApplet>;
159 using ErrorApplet = std::unique_ptr<Core::Frontend::ErrorApplet>; 161 using ErrorApplet = std::unique_ptr<Core::Frontend::ErrorApplet>;
162 using ParentalControlsApplet = std::unique_ptr<Core::Frontend::ParentalControlsApplet>;
160 using PhotoViewer = std::unique_ptr<Core::Frontend::PhotoViewerApplet>; 163 using PhotoViewer = std::unique_ptr<Core::Frontend::PhotoViewerApplet>;
161 using ProfileSelect = std::unique_ptr<Core::Frontend::ProfileSelectApplet>; 164 using ProfileSelect = std::unique_ptr<Core::Frontend::ProfileSelectApplet>;
162 using SoftwareKeyboard = std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet>; 165 using SoftwareKeyboard = std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet>;
163 using WebBrowser = std::unique_ptr<Core::Frontend::WebBrowserApplet>; 166 using WebBrowser = std::unique_ptr<Core::Frontend::WebBrowserApplet>;
164 using ECommerceApplet = std::unique_ptr<Core::Frontend::ECommerceApplet>;
165 167
166 AppletFrontendSet(); 168 AppletFrontendSet();
167 AppletFrontendSet(ParentalControlsApplet parental_controls, ErrorApplet error, 169 AppletFrontendSet(ControllerApplet controller, ECommerceApplet e_commerce, ErrorApplet error,
168 PhotoViewer photo_viewer, ProfileSelect profile_select, 170 ParentalControlsApplet parental_controls, PhotoViewer photo_viewer,
169 SoftwareKeyboard software_keyboard, WebBrowser web_browser, 171 ProfileSelect profile_select, SoftwareKeyboard software_keyboard,
170 ECommerceApplet e_commerce); 172 WebBrowser web_browser);
171 ~AppletFrontendSet(); 173 ~AppletFrontendSet();
172 174
173 AppletFrontendSet(const AppletFrontendSet&) = delete; 175 AppletFrontendSet(const AppletFrontendSet&) = delete;
@@ -176,13 +178,14 @@ struct AppletFrontendSet {
176 AppletFrontendSet(AppletFrontendSet&&) noexcept; 178 AppletFrontendSet(AppletFrontendSet&&) noexcept;
177 AppletFrontendSet& operator=(AppletFrontendSet&&) noexcept; 179 AppletFrontendSet& operator=(AppletFrontendSet&&) noexcept;
178 180
179 ParentalControlsApplet parental_controls; 181 ControllerApplet controller;
182 ECommerceApplet e_commerce;
180 ErrorApplet error; 183 ErrorApplet error;
184 ParentalControlsApplet parental_controls;
181 PhotoViewer photo_viewer; 185 PhotoViewer photo_viewer;
182 ProfileSelect profile_select; 186 ProfileSelect profile_select;
183 SoftwareKeyboard software_keyboard; 187 SoftwareKeyboard software_keyboard;
184 WebBrowser web_browser; 188 WebBrowser web_browser;
185 ECommerceApplet e_commerce;
186}; 189};
187 190
188class AppletManager { 191class AppletManager {
diff --git a/src/core/hle/service/am/applets/controller.cpp b/src/core/hle/service/am/applets/controller.cpp
new file mode 100644
index 000000000..2a45a388f
--- /dev/null
+++ b/src/core/hle/service/am/applets/controller.cpp
@@ -0,0 +1,197 @@
1// Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <algorithm>
6
7#include "common/string_util.h"
8#include "core/core.h"
9#include "core/frontend/applets/controller.h"
10#include "core/hle/service/am/am.h"
11#include "core/hle/service/am/applets/controller.h"
12#include "core/hle/service/hid/controllers/npad.h"
13
14namespace Service::AM::Applets {
15
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
21static Core::Frontend::ControllerParameters ConvertToFrontendParameters(
22 ControllerSupportArgPrivate private_arg, ControllerSupportArgHeader header,
23 std::vector<IdentificationColor> identification_colors) {
24 HID::Controller_NPad::NPadType npad_style_set;
25 npad_style_set.raw = private_arg.style_set;
26
27 return {
28 .min_players = header.player_count_min,
29 .max_players = header.player_count_max,
30 .keep_controllers_connected = header.enable_take_over_connection,
31 .enable_single_mode = header.enable_single_mode,
32 .enable_border_color = header.enable_identification_color,
33 .border_colors = identification_colors,
34 .allow_pro_controller = npad_style_set.pro_controller == 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
42Controller::Controller(Core::System& system_, const Core::Frontend::ControllerApplet& frontend_)
43 : Applet{system_.Kernel()}, frontend(frontend_) {}
44
45Controller::~Controller() = default;
46
47void Controller::Initialize() {
48 Applet::Initialize();
49
50 LOG_INFO(Service_HID, "Initializing Controller Applet.");
51
52 LOG_DEBUG(Service_HID,
53 "Initializing Applet with common_args: arg_version={}, lib_version={}, "
54 "play_startup_sound={}, size={}, system_tick={}, theme_color={}",
55 common_args.arguments_version, common_args.library_version,
56 common_args.play_startup_sound, common_args.size, common_args.system_tick,
57 common_args.theme_color);
58
59 library_applet_version = LibraryAppletVersion{common_args.library_version};
60
61 const auto private_arg_storage = broker.PopNormalDataToApplet();
62 ASSERT(private_arg_storage != nullptr);
63
64 const auto& private_arg = private_arg_storage->GetData();
65 ASSERT(private_arg.size() == sizeof(ControllerSupportArgPrivate));
66
67 std::memcpy(&controller_private_arg, private_arg.data(), sizeof(ControllerSupportArgPrivate));
68 ASSERT_MSG(controller_private_arg.arg_private_size == sizeof(ControllerSupportArgPrivate),
69 "Unknown ControllerSupportArgPrivate revision={} with size={}",
70 library_applet_version, controller_private_arg.arg_private_size);
71
72 switch (controller_private_arg.mode) {
73 case ControllerSupportMode::ShowControllerSupport: {
74 const auto user_arg_storage = broker.PopNormalDataToApplet();
75 ASSERT(user_arg_storage != nullptr);
76
77 const auto& user_arg = user_arg_storage->GetData();
78 switch (library_applet_version) {
79 case LibraryAppletVersion::Version3:
80 case LibraryAppletVersion::Version4:
81 case LibraryAppletVersion::Version5:
82 ASSERT(user_arg.size() == sizeof(ControllerSupportArgOld));
83 std::memcpy(&controller_user_arg_old, user_arg.data(), sizeof(ControllerSupportArgOld));
84 break;
85 case LibraryAppletVersion::Version7:
86 ASSERT(user_arg.size() == sizeof(ControllerSupportArgNew));
87 std::memcpy(&controller_user_arg_new, user_arg.data(), sizeof(ControllerSupportArgNew));
88 break;
89 default:
90 UNIMPLEMENTED_MSG("Unknown ControllerSupportArg revision={} with size={}",
91 library_applet_version, controller_private_arg.arg_size);
92 ASSERT(user_arg.size() >= sizeof(ControllerSupportArgNew));
93 std::memcpy(&controller_user_arg_new, user_arg.data(), sizeof(ControllerSupportArgNew));
94 break;
95 }
96 break;
97 }
98 case ControllerSupportMode::ShowControllerStrapGuide:
99 case ControllerSupportMode::ShowControllerFirmwareUpdate:
100 default: {
101 UNIMPLEMENTED_MSG("Unimplemented ControllerSupportMode={}", controller_private_arg.mode);
102 break;
103 }
104 }
105}
106
107bool Controller::TransactionComplete() const {
108 return complete;
109}
110
111ResultCode Controller::GetStatus() const {
112 return status;
113}
114
115void Controller::ExecuteInteractive() {
116 UNREACHABLE_MSG("Attempted to call interactive execution on non-interactive applet.");
117}
118
119void Controller::Execute() {
120 switch (controller_private_arg.mode) {
121 case ControllerSupportMode::ShowControllerSupport: {
122 const auto parameters = [this] {
123 switch (library_applet_version) {
124 case LibraryAppletVersion::Version3:
125 case LibraryAppletVersion::Version4:
126 case LibraryAppletVersion::Version5:
127 return ConvertToFrontendParameters(
128 controller_private_arg, controller_user_arg_old.header,
129 std::vector<IdentificationColor>(
130 controller_user_arg_old.identification_colors.begin(),
131 controller_user_arg_old.identification_colors.end()));
132 case LibraryAppletVersion::Version7:
133 default:
134 return ConvertToFrontendParameters(
135 controller_private_arg, controller_user_arg_new.header,
136 std::vector<IdentificationColor>(
137 controller_user_arg_new.identification_colors.begin(),
138 controller_user_arg_new.identification_colors.end()));
139 }
140 }();
141
142 is_single_mode = parameters.enable_single_mode;
143
144 LOG_DEBUG(
145 Service_HID,
146 "Controller Parameters: min_players={}, max_players={}, keep_controllers_connected={}, "
147 "enable_single_mode={}, enable_border_color={}, allow_pro_controller={}, "
148 "allow_handheld={}, allow_dual_joycons={}, allow_left_joycon={}, allow_right_joycon={}",
149 parameters.min_players, parameters.max_players, parameters.keep_controllers_connected,
150 parameters.enable_single_mode, parameters.enable_border_color,
151 parameters.allow_pro_controller, parameters.allow_handheld,
152 parameters.allow_dual_joycons, parameters.allow_left_joycon,
153 parameters.allow_right_joycon);
154
155 frontend.ReconfigureControllers([this] { ConfigurationComplete(); }, parameters);
156 break;
157 }
158 case ControllerSupportMode::ShowControllerStrapGuide:
159 case ControllerSupportMode::ShowControllerFirmwareUpdate:
160 default: {
161 ConfigurationComplete();
162 break;
163 }
164 }
165}
166
167void Controller::ConfigurationComplete() {
168 ControllerSupportResultInfo result_info{};
169
170 const auto& players = Settings::values.players;
171
172 // If enable_single_mode is enabled, player_count is 1 regardless of any other parameters.
173 // Otherwise, only count connected players from P1-P8.
174 result_info.player_count =
175 is_single_mode ? 1
176 : static_cast<s8>(std::count_if(
177 players.begin(), players.end() - 2,
178 [](Settings::PlayerInput player) { return player.connected; }));
179
180 result_info.selected_id = HID::Controller_NPad::IndexToNPad(
181 std::distance(players.begin(),
182 std::find_if(players.begin(), players.end(),
183 [](Settings::PlayerInput player) { return player.connected; })));
184
185 result_info.result = 0;
186
187 LOG_DEBUG(Service_HID, "Result Info: player_count={}, selected_id={}, result={}",
188 result_info.player_count, result_info.selected_id, result_info.result);
189
190 complete = true;
191 out_data = std::vector<u8>(sizeof(ControllerSupportResultInfo));
192 std::memcpy(out_data.data(), &result_info, out_data.size());
193 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::move(out_data)));
194 broker.SignalStateChanged();
195}
196
197} // namespace Service::AM::Applets
diff --git a/src/core/hle/service/am/applets/controller.h b/src/core/hle/service/am/applets/controller.h
new file mode 100644
index 000000000..90a78d508
--- /dev/null
+++ b/src/core/hle/service/am/applets/controller.h
@@ -0,0 +1,119 @@
1// Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <array>
8
9#include "core/hle/result.h"
10#include "core/hle/service/am/applets/applets.h"
11
12namespace Core {
13class System;
14}
15
16namespace Service::AM::Applets {
17
18using IdentificationColor = std::array<u8, 4>;
19
20enum class LibraryAppletVersion : u32_le {
21 Version3 = 0x3, // 1.0.0 - 2.3.0
22 Version4 = 0x4, // 3.0.0 - 5.1.0
23 Version5 = 0x5, // 6.0.0 - 7.0.1
24 Version7 = 0x7, // 8.0.0+
25};
26
27enum class ControllerSupportMode : u8 {
28 ShowControllerSupport = 0,
29 ShowControllerStrapGuide = 1,
30 ShowControllerFirmwareUpdate = 2,
31};
32
33enum class ControllerSupportCaller : u8 {
34 Application = 0,
35 System = 1,
36};
37
38struct ControllerSupportArgPrivate {
39 u32 arg_private_size{};
40 u32 arg_size{};
41 bool flag_0{};
42 bool flag_1{};
43 ControllerSupportMode mode{};
44 ControllerSupportCaller caller{};
45 u32 style_set{};
46 u32 joy_hold_type{};
47};
48static_assert(sizeof(ControllerSupportArgPrivate) == 0x14,
49 "ControllerSupportArgPrivate has incorrect size.");
50
51struct ControllerSupportArgHeader {
52 s8 player_count_min{};
53 s8 player_count_max{};
54 bool enable_take_over_connection{};
55 bool enable_left_justify{};
56 bool enable_permit_joy_dual{};
57 bool enable_single_mode{};
58 bool enable_identification_color{};
59};
60static_assert(sizeof(ControllerSupportArgHeader) == 0x7,
61 "ControllerSupportArgHeader has incorrect size.");
62
63// LibraryAppletVersion 0x3, 0x4, 0x5
64struct ControllerSupportArgOld {
65 ControllerSupportArgHeader header{};
66 std::array<IdentificationColor, 4> identification_colors{};
67 bool enable_explain_text{};
68 std::array<std::array<char, 0x81>, 4> explain_text{};
69};
70static_assert(sizeof(ControllerSupportArgOld) == 0x21C,
71 "ControllerSupportArgOld has incorrect size.");
72
73// LibraryAppletVersion 0x7
74struct ControllerSupportArgNew {
75 ControllerSupportArgHeader header{};
76 std::array<IdentificationColor, 8> identification_colors{};
77 bool enable_explain_text{};
78 std::array<std::array<char, 0x81>, 8> explain_text{};
79};
80static_assert(sizeof(ControllerSupportArgNew) == 0x430,
81 "ControllerSupportArgNew has incorrect size.");
82
83struct ControllerSupportResultInfo {
84 s8 player_count{};
85 INSERT_PADDING_BYTES(3);
86 u32 selected_id{};
87 u32 result{};
88};
89static_assert(sizeof(ControllerSupportResultInfo) == 0xC,
90 "ControllerSupportResultInfo has incorrect size.");
91
92class Controller final : public Applet {
93public:
94 explicit Controller(Core::System& system_, const Core::Frontend::ControllerApplet& frontend_);
95 ~Controller() override;
96
97 void Initialize() override;
98
99 bool TransactionComplete() const override;
100 ResultCode GetStatus() const override;
101 void ExecuteInteractive() override;
102 void Execute() override;
103
104 void ConfigurationComplete();
105
106private:
107 const Core::Frontend::ControllerApplet& frontend;
108
109 LibraryAppletVersion library_applet_version;
110 ControllerSupportArgPrivate controller_private_arg;
111 ControllerSupportArgOld controller_user_arg_old;
112 ControllerSupportArgNew controller_user_arg_new;
113 bool complete{false};
114 ResultCode status{RESULT_SUCCESS};
115 bool is_single_mode{false};
116 std::vector<u8> out_data;
117};
118
119} // namespace Service::AM::Applets
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index 45fde8df2..efb953d93 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -193,7 +193,8 @@ void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) {
193 controller.battery_level[0] = BATTERY_FULL; 193 controller.battery_level[0] = BATTERY_FULL;
194 controller.battery_level[1] = BATTERY_FULL; 194 controller.battery_level[1] = BATTERY_FULL;
195 controller.battery_level[2] = BATTERY_FULL; 195 controller.battery_level[2] = BATTERY_FULL;
196 styleset_changed_events[controller_idx].writable->Signal(); 196
197 SignalStyleSetChangedEvent(IndexToNPad(controller_idx));
197} 198}
198 199
199void Controller_NPad::OnInit() { 200void Controller_NPad::OnInit() {
@@ -518,13 +519,17 @@ void Controller_NPad::VibrateController(const std::vector<u32>& controller_ids,
518 last_processed_vibration = vibrations.back(); 519 last_processed_vibration = vibrations.back();
519} 520}
520 521
522Controller_NPad::Vibration Controller_NPad::GetLastVibration() const {
523 return last_processed_vibration;
524}
525
521std::shared_ptr<Kernel::ReadableEvent> Controller_NPad::GetStyleSetChangedEvent(u32 npad_id) const { 526std::shared_ptr<Kernel::ReadableEvent> Controller_NPad::GetStyleSetChangedEvent(u32 npad_id) const {
522 const auto& styleset_event = styleset_changed_events[NPadIdToIndex(npad_id)]; 527 const auto& styleset_event = styleset_changed_events[NPadIdToIndex(npad_id)];
523 return styleset_event.readable; 528 return styleset_event.readable;
524} 529}
525 530
526Controller_NPad::Vibration Controller_NPad::GetLastVibration() const { 531void Controller_NPad::SignalStyleSetChangedEvent(u32 npad_id) const {
527 return last_processed_vibration; 532 styleset_changed_events[NPadIdToIndex(npad_id)].writable->Signal();
528} 533}
529 534
530void Controller_NPad::AddNewControllerAt(NPadControllerType controller, std::size_t npad_index) { 535void Controller_NPad::AddNewControllerAt(NPadControllerType controller, std::size_t npad_index) {
@@ -534,7 +539,7 @@ void Controller_NPad::AddNewControllerAt(NPadControllerType controller, std::siz
534void Controller_NPad::UpdateControllerAt(NPadControllerType controller, std::size_t npad_index, 539void Controller_NPad::UpdateControllerAt(NPadControllerType controller, std::size_t npad_index,
535 bool connected) { 540 bool connected) {
536 if (!connected) { 541 if (!connected) {
537 DisconnectNPad(IndexToNPad(npad_index)); 542 DisconnectNPadAtIndex(npad_index);
538 return; 543 return;
539 } 544 }
540 545
@@ -554,16 +559,19 @@ void Controller_NPad::UpdateControllerAt(NPadControllerType controller, std::siz
554} 559}
555 560
556void Controller_NPad::DisconnectNPad(u32 npad_id) { 561void Controller_NPad::DisconnectNPad(u32 npad_id) {
557 const auto npad_index = NPadIdToIndex(npad_id); 562 DisconnectNPadAtIndex(NPadIdToIndex(npad_id));
558 connected_controllers[npad_index].is_connected = false; 563}
564
565void Controller_NPad::DisconnectNPadAtIndex(std::size_t npad_index) {
559 Settings::values.players[npad_index].connected = false; 566 Settings::values.players[npad_index].connected = false;
567 connected_controllers[npad_index].is_connected = false;
560 568
561 auto& controller = shared_memory_entries[npad_index]; 569 auto& controller = shared_memory_entries[npad_index];
562 controller.joy_styles.raw = 0; // Zero out 570 controller.joy_styles.raw = 0; // Zero out
563 controller.device_type.raw = 0; 571 controller.device_type.raw = 0;
564 controller.properties.raw = 0; 572 controller.properties.raw = 0;
565 573
566 styleset_changed_events[npad_index].writable->Signal(); 574 SignalStyleSetChangedEvent(IndexToNPad(npad_index));
567} 575}
568 576
569void Controller_NPad::SetGyroscopeZeroDriftMode(GyroscopeZeroDriftMode drift_mode) { 577void Controller_NPad::SetGyroscopeZeroDriftMode(GyroscopeZeroDriftMode drift_mode) {
@@ -650,13 +658,13 @@ void Controller_NPad::ClearAllConnectedControllers() {
650} 658}
651 659
652void Controller_NPad::DisconnectAllConnectedControllers() { 660void Controller_NPad::DisconnectAllConnectedControllers() {
653 for (ControllerHolder& controller : connected_controllers) { 661 for (auto& controller : connected_controllers) {
654 controller.is_connected = false; 662 controller.is_connected = false;
655 } 663 }
656} 664}
657 665
658void Controller_NPad::ConnectAllDisconnectedControllers() { 666void Controller_NPad::ConnectAllDisconnectedControllers() {
659 for (ControllerHolder& controller : connected_controllers) { 667 for (auto& controller : connected_controllers) {
660 if (controller.type != NPadControllerType::None && !controller.is_connected) { 668 if (controller.type != NPadControllerType::None && !controller.is_connected) {
661 controller.is_connected = true; 669 controller.is_connected = true;
662 } 670 }
@@ -664,7 +672,7 @@ void Controller_NPad::ConnectAllDisconnectedControllers() {
664} 672}
665 673
666void Controller_NPad::ClearAllControllers() { 674void Controller_NPad::ClearAllControllers() {
667 for (ControllerHolder& controller : connected_controllers) { 675 for (auto& controller : connected_controllers) {
668 controller.type = NPadControllerType::None; 676 controller.type = NPadControllerType::None;
669 controller.is_connected = false; 677 controller.is_connected = false;
670 } 678 }
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h
index 75ce5b731..40c763376 100644
--- a/src/core/hle/service/hid/controllers/npad.h
+++ b/src/core/hle/service/hid/controllers/npad.h
@@ -115,15 +115,19 @@ public:
115 void VibrateController(const std::vector<u32>& controller_ids, 115 void VibrateController(const std::vector<u32>& controller_ids,
116 const std::vector<Vibration>& vibrations); 116 const std::vector<Vibration>& vibrations);
117 117
118 std::shared_ptr<Kernel::ReadableEvent> GetStyleSetChangedEvent(u32 npad_id) const;
119 Vibration GetLastVibration() const; 118 Vibration GetLastVibration() const;
120 119
120 std::shared_ptr<Kernel::ReadableEvent> GetStyleSetChangedEvent(u32 npad_id) const;
121 void SignalStyleSetChangedEvent(u32 npad_id) const;
122
121 // Adds a new controller at an index. 123 // Adds a new controller at an index.
122 void AddNewControllerAt(NPadControllerType controller, std::size_t npad_index); 124 void AddNewControllerAt(NPadControllerType controller, std::size_t npad_index);
123 // Adds a new controller at an index with connection status. 125 // Adds a new controller at an index with connection status.
124 void UpdateControllerAt(NPadControllerType controller, std::size_t npad_index, bool connected); 126 void UpdateControllerAt(NPadControllerType controller, std::size_t npad_index, bool connected);
125 127
126 void DisconnectNPad(u32 npad_id); 128 void DisconnectNPad(u32 npad_id);
129 void DisconnectNPadAtIndex(std::size_t index);
130
127 void SetGyroscopeZeroDriftMode(GyroscopeZeroDriftMode drift_mode); 131 void SetGyroscopeZeroDriftMode(GyroscopeZeroDriftMode drift_mode);
128 GyroscopeZeroDriftMode GetGyroscopeZeroDriftMode() const; 132 GyroscopeZeroDriftMode GetGyroscopeZeroDriftMode() const;
129 LedPattern GetLedPattern(u32 npad_id); 133 LedPattern GetLedPattern(u32 npad_id);