diff options
| author | 2020-08-21 07:39:24 -0400 | |
|---|---|---|
| committer | 2020-09-04 12:23:25 -0400 | |
| commit | 5219615418920be8502aa24507572cf0930d65ea (patch) | |
| tree | d15e05d0bf328d5e289409977cf07b30ca84fe7e /src/core | |
| parent | Merge pull request #4596 from FearlessTobi/port-5495 (diff) | |
| download | yuzu-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.txt | 4 | ||||
| -rw-r--r-- | src/core/frontend/applets/controller.cpp | 40 | ||||
| -rw-r--r-- | src/core/frontend/applets/controller.h | 45 | ||||
| -rw-r--r-- | src/core/hle/service/am/applets/applets.cpp | 71 | ||||
| -rw-r--r-- | src/core/hle/service/am/applets/applets.h | 19 | ||||
| -rw-r--r-- | src/core/hle/service/am/applets/controller.cpp | 197 | ||||
| -rw-r--r-- | src/core/hle/service/am/applets/controller.h | 119 | ||||
| -rw-r--r-- | src/core/hle/service/hid/controllers/npad.cpp | 28 | ||||
| -rw-r--r-- | src/core/hle/service/hid/controllers/npad.h | 6 |
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 | |||
| 11 | namespace Core::Frontend { | ||
| 12 | |||
| 13 | ControllerApplet::~ControllerApplet() = default; | ||
| 14 | |||
| 15 | DefaultControllerApplet::~DefaultControllerApplet() = default; | ||
| 16 | |||
| 17 | void 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 | |||
| 11 | namespace Core::Frontend { | ||
| 12 | |||
| 13 | using BorderColor = std::array<u8, 4>; | ||
| 14 | |||
| 15 | struct 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 | |||
| 29 | class ControllerApplet { | ||
| 30 | public: | ||
| 31 | virtual ~ControllerApplet(); | ||
| 32 | |||
| 33 | virtual void ReconfigureControllers(std::function<void()> callback, | ||
| 34 | ControllerParameters parameters) const = 0; | ||
| 35 | }; | ||
| 36 | |||
| 37 | class DefaultControllerApplet final : public ControllerApplet { | ||
| 38 | public: | ||
| 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 | ||
| 141 | AppletFrontendSet::AppletFrontendSet() = default; | 143 | AppletFrontendSet::AppletFrontendSet() = default; |
| 142 | 144 | ||
| 143 | AppletFrontendSet::AppletFrontendSet(ParentalControlsApplet parental_controls, ErrorApplet error, | 145 | AppletFrontendSet::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 | ||
| 152 | AppletFrontendSet::~AppletFrontendSet() = default; | 154 | AppletFrontendSet::~AppletFrontendSet() = default; |
| 153 | 155 | ||
| @@ -164,20 +166,37 @@ const AppletFrontendSet& AppletManager::GetAppletFrontendSet() const { | |||
| 164 | } | 166 | } |
| 165 | 167 | ||
| 166 | void AppletManager::SetAppletFrontendSet(AppletFrontendSet set) { | 168 | void 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 | ||
| 183 | void AppletManager::SetDefaultAppletFrontendSet() { | 202 | void AppletManager::SetDefaultAppletFrontendSet() { |
| @@ -186,15 +205,23 @@ void AppletManager::SetDefaultAppletFrontendSet() { | |||
| 186 | } | 205 | } |
| 187 | 206 | ||
| 188 | void AppletManager::SetDefaultAppletsIfMissing() { | 207 | void 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 | ||
| 220 | void AppletManager::ClearAll() { | 243 | void 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 | ||
| 19 | namespace Core::Frontend { | 19 | namespace Core::Frontend { |
| 20 | class ControllerApplet; | ||
| 20 | class ECommerceApplet; | 21 | class ECommerceApplet; |
| 21 | class ErrorApplet; | 22 | class ErrorApplet; |
| 22 | class ParentalControlsApplet; | 23 | class ParentalControlsApplet; |
| @@ -155,19 +156,20 @@ protected: | |||
| 155 | }; | 156 | }; |
| 156 | 157 | ||
| 157 | struct AppletFrontendSet { | 158 | struct 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 | ||
| 188 | class AppletManager { | 191 | class 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 | |||
| 14 | namespace 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 | |||
| 21 | static 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 | |||
| 42 | Controller::Controller(Core::System& system_, const Core::Frontend::ControllerApplet& frontend_) | ||
| 43 | : Applet{system_.Kernel()}, frontend(frontend_) {} | ||
| 44 | |||
| 45 | Controller::~Controller() = default; | ||
| 46 | |||
| 47 | void 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 | |||
| 107 | bool Controller::TransactionComplete() const { | ||
| 108 | return complete; | ||
| 109 | } | ||
| 110 | |||
| 111 | ResultCode Controller::GetStatus() const { | ||
| 112 | return status; | ||
| 113 | } | ||
| 114 | |||
| 115 | void Controller::ExecuteInteractive() { | ||
| 116 | UNREACHABLE_MSG("Attempted to call interactive execution on non-interactive applet."); | ||
| 117 | } | ||
| 118 | |||
| 119 | void 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 | |||
| 167 | void 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 | |||
| 12 | namespace Core { | ||
| 13 | class System; | ||
| 14 | } | ||
| 15 | |||
| 16 | namespace Service::AM::Applets { | ||
| 17 | |||
| 18 | using IdentificationColor = std::array<u8, 4>; | ||
| 19 | |||
| 20 | enum 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 | |||
| 27 | enum class ControllerSupportMode : u8 { | ||
| 28 | ShowControllerSupport = 0, | ||
| 29 | ShowControllerStrapGuide = 1, | ||
| 30 | ShowControllerFirmwareUpdate = 2, | ||
| 31 | }; | ||
| 32 | |||
| 33 | enum class ControllerSupportCaller : u8 { | ||
| 34 | Application = 0, | ||
| 35 | System = 1, | ||
| 36 | }; | ||
| 37 | |||
| 38 | struct 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 | }; | ||
| 48 | static_assert(sizeof(ControllerSupportArgPrivate) == 0x14, | ||
| 49 | "ControllerSupportArgPrivate has incorrect size."); | ||
| 50 | |||
| 51 | struct 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 | }; | ||
| 60 | static_assert(sizeof(ControllerSupportArgHeader) == 0x7, | ||
| 61 | "ControllerSupportArgHeader has incorrect size."); | ||
| 62 | |||
| 63 | // LibraryAppletVersion 0x3, 0x4, 0x5 | ||
| 64 | struct 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 | }; | ||
| 70 | static_assert(sizeof(ControllerSupportArgOld) == 0x21C, | ||
| 71 | "ControllerSupportArgOld has incorrect size."); | ||
| 72 | |||
| 73 | // LibraryAppletVersion 0x7 | ||
| 74 | struct 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 | }; | ||
| 80 | static_assert(sizeof(ControllerSupportArgNew) == 0x430, | ||
| 81 | "ControllerSupportArgNew has incorrect size."); | ||
| 82 | |||
| 83 | struct ControllerSupportResultInfo { | ||
| 84 | s8 player_count{}; | ||
| 85 | INSERT_PADDING_BYTES(3); | ||
| 86 | u32 selected_id{}; | ||
| 87 | u32 result{}; | ||
| 88 | }; | ||
| 89 | static_assert(sizeof(ControllerSupportResultInfo) == 0xC, | ||
| 90 | "ControllerSupportResultInfo has incorrect size."); | ||
| 91 | |||
| 92 | class Controller final : public Applet { | ||
| 93 | public: | ||
| 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 | |||
| 106 | private: | ||
| 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 | ||
| 199 | void Controller_NPad::OnInit() { | 200 | void 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 | ||
| 522 | Controller_NPad::Vibration Controller_NPad::GetLastVibration() const { | ||
| 523 | return last_processed_vibration; | ||
| 524 | } | ||
| 525 | |||
| 521 | std::shared_ptr<Kernel::ReadableEvent> Controller_NPad::GetStyleSetChangedEvent(u32 npad_id) const { | 526 | std::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 | ||
| 526 | Controller_NPad::Vibration Controller_NPad::GetLastVibration() const { | 531 | void 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 | ||
| 530 | void Controller_NPad::AddNewControllerAt(NPadControllerType controller, std::size_t npad_index) { | 535 | void Controller_NPad::AddNewControllerAt(NPadControllerType controller, std::size_t npad_index) { |
| @@ -534,7 +539,7 @@ void Controller_NPad::AddNewControllerAt(NPadControllerType controller, std::siz | |||
| 534 | void Controller_NPad::UpdateControllerAt(NPadControllerType controller, std::size_t npad_index, | 539 | void 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 | ||
| 556 | void Controller_NPad::DisconnectNPad(u32 npad_id) { | 561 | void 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 | |||
| 565 | void 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 | ||
| 569 | void Controller_NPad::SetGyroscopeZeroDriftMode(GyroscopeZeroDriftMode drift_mode) { | 577 | void Controller_NPad::SetGyroscopeZeroDriftMode(GyroscopeZeroDriftMode drift_mode) { |
| @@ -650,13 +658,13 @@ void Controller_NPad::ClearAllConnectedControllers() { | |||
| 650 | } | 658 | } |
| 651 | 659 | ||
| 652 | void Controller_NPad::DisconnectAllConnectedControllers() { | 660 | void 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 | ||
| 658 | void Controller_NPad::ConnectAllDisconnectedControllers() { | 666 | void 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 | ||
| 666 | void Controller_NPad::ClearAllControllers() { | 674 | void 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); |