summaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-rw-r--r--src/core/frontend/applets/controller.cpp8
-rw-r--r--src/core/frontend/framebuffer_layout.cpp2
-rw-r--r--src/core/frontend/input.h9
-rw-r--r--src/core/hle/service/am/am.cpp4
-rw-r--r--src/core/hle/service/am/applets/controller.cpp4
-rw-r--r--src/core/hle/service/apm/controller.cpp3
-rw-r--r--src/core/hle/service/hid/controllers/npad.cpp270
-rw-r--r--src/core/hle/service/hid/controllers/npad.h131
-rw-r--r--src/core/hle/service/hid/hid.cpp703
-rw-r--r--src/core/hle/service/hid/hid.h37
-rw-r--r--src/core/hle/service/vi/vi.cpp2
-rw-r--r--src/core/settings.cpp8
-rw-r--r--src/core/settings.h58
-rw-r--r--src/core/telemetry_session.cpp2
14 files changed, 857 insertions, 384 deletions
diff --git a/src/core/frontend/applets/controller.cpp b/src/core/frontend/applets/controller.cpp
index 5582091f4..03bbedf8b 100644
--- a/src/core/frontend/applets/controller.cpp
+++ b/src/core/frontend/applets/controller.cpp
@@ -27,19 +27,19 @@ void DefaultControllerApplet::ReconfigureControllers(std::function<void()> callb
27 ->GetAppletResource() 27 ->GetAppletResource()
28 ->GetController<Service::HID::Controller_NPad>(Service::HID::HidController::NPad); 28 ->GetController<Service::HID::Controller_NPad>(Service::HID::HidController::NPad);
29 29
30 auto& players = Settings::values.players; 30 auto& players = Settings::values.players.GetValue();
31 31
32 const std::size_t min_supported_players = 32 const std::size_t min_supported_players =
33 parameters.enable_single_mode ? 1 : parameters.min_players; 33 parameters.enable_single_mode ? 1 : parameters.min_players;
34 34
35 // Disconnect Handheld first. 35 // Disconnect Handheld first.
36 npad.DisconnectNPadAtIndex(8); 36 npad.DisconnectNpadAtIndex(8);
37 37
38 // Deduce the best configuration based on the input parameters. 38 // Deduce the best configuration based on the input parameters.
39 for (std::size_t index = 0; index < players.size() - 2; ++index) { 39 for (std::size_t index = 0; index < players.size() - 2; ++index) {
40 // First, disconnect all controllers regardless of the value of keep_controllers_connected. 40 // First, disconnect all controllers regardless of the value of keep_controllers_connected.
41 // This makes it easy to connect the desired controllers. 41 // This makes it easy to connect the desired controllers.
42 npad.DisconnectNPadAtIndex(index); 42 npad.DisconnectNpadAtIndex(index);
43 43
44 // Only connect the minimum number of required players. 44 // Only connect the minimum number of required players.
45 if (index >= min_supported_players) { 45 if (index >= min_supported_players) {
@@ -66,7 +66,7 @@ void DefaultControllerApplet::ReconfigureControllers(std::function<void()> callb
66 npad.MapSettingsTypeToNPad(Settings::ControllerType::RightJoycon), index); 66 npad.MapSettingsTypeToNPad(Settings::ControllerType::RightJoycon), index);
67 } 67 }
68 } else if (index == 0 && parameters.enable_single_mode && parameters.allow_handheld && 68 } else if (index == 0 && parameters.enable_single_mode && parameters.allow_handheld &&
69 !Settings::values.use_docked_mode) { 69 !Settings::values.use_docked_mode.GetValue()) {
70 // We should *never* reach here under any normal circumstances. 70 // We should *never* reach here under any normal circumstances.
71 npad.AddNewControllerAt(npad.MapSettingsTypeToNPad(Settings::ControllerType::Handheld), 71 npad.AddNewControllerAt(npad.MapSettingsTypeToNPad(Settings::ControllerType::Handheld),
72 index); 72 index);
diff --git a/src/core/frontend/framebuffer_layout.cpp b/src/core/frontend/framebuffer_layout.cpp
index 1acc82497..b9a270a55 100644
--- a/src/core/frontend/framebuffer_layout.cpp
+++ b/src/core/frontend/framebuffer_layout.cpp
@@ -47,7 +47,7 @@ FramebufferLayout DefaultFrameLayout(u32 width, u32 height) {
47FramebufferLayout FrameLayoutFromResolutionScale(u32 res_scale) { 47FramebufferLayout FrameLayoutFromResolutionScale(u32 res_scale) {
48 u32 width, height; 48 u32 width, height;
49 49
50 if (Settings::values.use_docked_mode) { 50 if (Settings::values.use_docked_mode.GetValue()) {
51 width = ScreenDocked::Width * res_scale; 51 width = ScreenDocked::Width * res_scale;
52 height = ScreenDocked::Height * res_scale; 52 height = ScreenDocked::Height * res_scale;
53 } else { 53 } else {
diff --git a/src/core/frontend/input.h b/src/core/frontend/input.h
index 277b70e53..25ac5af46 100644
--- a/src/core/frontend/input.h
+++ b/src/core/frontend/input.h
@@ -33,7 +33,7 @@ public:
33 virtual bool GetAnalogDirectionStatus(AnalogDirection direction) const { 33 virtual bool GetAnalogDirectionStatus(AnalogDirection direction) const {
34 return {}; 34 return {};
35 } 35 }
36 virtual bool SetRumblePlay(f32 amp_high, f32 amp_low, f32 freq_high, f32 freq_low) const { 36 virtual bool SetRumblePlay(f32 amp_low, f32 freq_low, f32 amp_high, f32 freq_high) const {
37 return {}; 37 return {};
38 } 38 }
39}; 39};
@@ -122,6 +122,13 @@ using ButtonDevice = InputDevice<bool>;
122using AnalogDevice = InputDevice<std::tuple<float, float>>; 122using AnalogDevice = InputDevice<std::tuple<float, float>>;
123 123
124/** 124/**
125 * A vibration device is an input device that returns an unsigned byte as status.
126 * It represents whether the vibration device supports vibration or not.
127 * If the status returns 1, it supports vibration. Otherwise, it does not support vibration.
128 */
129using VibrationDevice = InputDevice<u8>;
130
131/**
125 * A motion status is an object that returns a tuple of accelerometer state vector, 132 * A motion status is an object that returns a tuple of accelerometer state vector,
126 * gyroscope state vector, rotation state vector and orientation state matrix. 133 * gyroscope state vector, rotation state vector and orientation state matrix.
127 * 134 *
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index 2ce742e35..eb097738a 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -751,7 +751,7 @@ void ICommonStateGetter::GetDefaultDisplayResolution(Kernel::HLERequestContext&
751 IPC::ResponseBuilder rb{ctx, 4}; 751 IPC::ResponseBuilder rb{ctx, 4};
752 rb.Push(RESULT_SUCCESS); 752 rb.Push(RESULT_SUCCESS);
753 753
754 if (Settings::values.use_docked_mode) { 754 if (Settings::values.use_docked_mode.GetValue()) {
755 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth) * 755 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth) *
756 static_cast<u32>(Settings::values.resolution_factor.GetValue())); 756 static_cast<u32>(Settings::values.resolution_factor.GetValue()));
757 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight) * 757 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight) *
@@ -824,7 +824,7 @@ void IStorage::Open(Kernel::HLERequestContext& ctx) {
824} 824}
825 825
826void ICommonStateGetter::GetOperationMode(Kernel::HLERequestContext& ctx) { 826void ICommonStateGetter::GetOperationMode(Kernel::HLERequestContext& ctx) {
827 const bool use_docked_mode{Settings::values.use_docked_mode}; 827 const bool use_docked_mode{Settings::values.use_docked_mode.GetValue()};
828 LOG_DEBUG(Service_AM, "called, use_docked_mode={}", use_docked_mode); 828 LOG_DEBUG(Service_AM, "called, use_docked_mode={}", use_docked_mode);
829 829
830 IPC::ResponseBuilder rb{ctx, 3}; 830 IPC::ResponseBuilder rb{ctx, 3};
diff --git a/src/core/hle/service/am/applets/controller.cpp b/src/core/hle/service/am/applets/controller.cpp
index a0152b4ea..3ca63f020 100644
--- a/src/core/hle/service/am/applets/controller.cpp
+++ b/src/core/hle/service/am/applets/controller.cpp
@@ -25,7 +25,7 @@ namespace Service::AM::Applets {
25static Core::Frontend::ControllerParameters ConvertToFrontendParameters( 25static Core::Frontend::ControllerParameters ConvertToFrontendParameters(
26 ControllerSupportArgPrivate private_arg, ControllerSupportArgHeader header, bool enable_text, 26 ControllerSupportArgPrivate private_arg, ControllerSupportArgHeader header, bool enable_text,
27 std::vector<IdentificationColor> identification_colors, std::vector<ExplainText> text) { 27 std::vector<IdentificationColor> identification_colors, std::vector<ExplainText> text) {
28 HID::Controller_NPad::NPadType npad_style_set; 28 HID::Controller_NPad::NpadStyleSet npad_style_set;
29 npad_style_set.raw = private_arg.style_set; 29 npad_style_set.raw = private_arg.style_set;
30 30
31 return { 31 return {
@@ -222,7 +222,7 @@ void Controller::Execute() {
222void Controller::ConfigurationComplete() { 222void Controller::ConfigurationComplete() {
223 ControllerSupportResultInfo result_info{}; 223 ControllerSupportResultInfo result_info{};
224 224
225 const auto& players = Settings::values.players; 225 const auto& players = Settings::values.players.GetValue();
226 226
227 // If enable_single_mode is enabled, player_count is 1 regardless of any other parameters. 227 // If enable_single_mode is enabled, player_count is 1 regardless of any other parameters.
228 // Otherwise, only count connected players from P1-P8. 228 // Otherwise, only count connected players from P1-P8.
diff --git a/src/core/hle/service/apm/controller.cpp b/src/core/hle/service/apm/controller.cpp
index 25a886238..ce993bad3 100644
--- a/src/core/hle/service/apm/controller.cpp
+++ b/src/core/hle/service/apm/controller.cpp
@@ -69,7 +69,8 @@ void Controller::SetFromCpuBoostMode(CpuBoostMode mode) {
69} 69}
70 70
71PerformanceMode Controller::GetCurrentPerformanceMode() const { 71PerformanceMode Controller::GetCurrentPerformanceMode() const {
72 return Settings::values.use_docked_mode ? PerformanceMode::Docked : PerformanceMode::Handheld; 72 return Settings::values.use_docked_mode.GetValue() ? PerformanceMode::Docked
73 : PerformanceMode::Handheld;
73} 74}
74 75
75PerformanceConfiguration Controller::GetCurrentPerformanceConfiguration(PerformanceMode mode) { 76PerformanceConfiguration Controller::GetCurrentPerformanceConfiguration(PerformanceMode mode) {
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index e311bc18c..e2539ded8 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -117,7 +117,10 @@ u32 Controller_NPad::IndexToNPad(std::size_t index) {
117} 117}
118 118
119Controller_NPad::Controller_NPad(Core::System& system) : ControllerBase(system), system(system) {} 119Controller_NPad::Controller_NPad(Core::System& system) : ControllerBase(system), system(system) {}
120Controller_NPad::~Controller_NPad() = default; 120
121Controller_NPad::~Controller_NPad() {
122 OnRelease();
123}
121 124
122void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) { 125void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) {
123 const auto controller_type = connected_controllers[controller_idx].type; 126 const auto controller_type = connected_controllers[controller_idx].type;
@@ -139,7 +142,7 @@ void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) {
139 controller.properties.is_vertical.Assign(1); 142 controller.properties.is_vertical.Assign(1);
140 controller.properties.use_plus.Assign(1); 143 controller.properties.use_plus.Assign(1);
141 controller.properties.use_minus.Assign(1); 144 controller.properties.use_minus.Assign(1);
142 controller.pad_assignment = NPadAssignments::Single; 145 controller.pad_assignment = NpadAssignments::Single;
143 break; 146 break;
144 case NPadControllerType::Handheld: 147 case NPadControllerType::Handheld:
145 controller.joy_styles.handheld.Assign(1); 148 controller.joy_styles.handheld.Assign(1);
@@ -147,7 +150,7 @@ void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) {
147 controller.properties.is_vertical.Assign(1); 150 controller.properties.is_vertical.Assign(1);
148 controller.properties.use_plus.Assign(1); 151 controller.properties.use_plus.Assign(1);
149 controller.properties.use_minus.Assign(1); 152 controller.properties.use_minus.Assign(1);
150 controller.pad_assignment = NPadAssignments::Dual; 153 controller.pad_assignment = NpadAssignments::Dual;
151 break; 154 break;
152 case NPadControllerType::JoyDual: 155 case NPadControllerType::JoyDual:
153 controller.joy_styles.joycon_dual.Assign(1); 156 controller.joy_styles.joycon_dual.Assign(1);
@@ -156,26 +159,26 @@ void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) {
156 controller.properties.is_vertical.Assign(1); 159 controller.properties.is_vertical.Assign(1);
157 controller.properties.use_plus.Assign(1); 160 controller.properties.use_plus.Assign(1);
158 controller.properties.use_minus.Assign(1); 161 controller.properties.use_minus.Assign(1);
159 controller.pad_assignment = NPadAssignments::Dual; 162 controller.pad_assignment = NpadAssignments::Dual;
160 break; 163 break;
161 case NPadControllerType::JoyLeft: 164 case NPadControllerType::JoyLeft:
162 controller.joy_styles.joycon_left.Assign(1); 165 controller.joy_styles.joycon_left.Assign(1);
163 controller.device_type.joycon_left.Assign(1); 166 controller.device_type.joycon_left.Assign(1);
164 controller.properties.is_horizontal.Assign(1); 167 controller.properties.is_horizontal.Assign(1);
165 controller.properties.use_minus.Assign(1); 168 controller.properties.use_minus.Assign(1);
166 controller.pad_assignment = NPadAssignments::Single; 169 controller.pad_assignment = NpadAssignments::Single;
167 break; 170 break;
168 case NPadControllerType::JoyRight: 171 case NPadControllerType::JoyRight:
169 controller.joy_styles.joycon_right.Assign(1); 172 controller.joy_styles.joycon_right.Assign(1);
170 controller.device_type.joycon_right.Assign(1); 173 controller.device_type.joycon_right.Assign(1);
171 controller.properties.is_horizontal.Assign(1); 174 controller.properties.is_horizontal.Assign(1);
172 controller.properties.use_plus.Assign(1); 175 controller.properties.use_plus.Assign(1);
173 controller.pad_assignment = NPadAssignments::Single; 176 controller.pad_assignment = NpadAssignments::Single;
174 break; 177 break;
175 case NPadControllerType::Pokeball: 178 case NPadControllerType::Pokeball:
176 controller.joy_styles.pokeball.Assign(1); 179 controller.joy_styles.pokeball.Assign(1);
177 controller.device_type.pokeball.Assign(1); 180 controller.device_type.pokeball.Assign(1);
178 controller.pad_assignment = NPadAssignments::Single; 181 controller.pad_assignment = NpadAssignments::Single;
179 break; 182 break;
180 } 183 }
181 184
@@ -184,11 +187,14 @@ void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) {
184 controller.single_color.button_color = 0; 187 controller.single_color.button_color = 0;
185 188
186 controller.dual_color_error = ColorReadError::ReadOk; 189 controller.dual_color_error = ColorReadError::ReadOk;
187 controller.left_color.body_color = Settings::values.players[controller_idx].body_color_left; 190 controller.left_color.body_color =
188 controller.left_color.button_color = Settings::values.players[controller_idx].button_color_left; 191 Settings::values.players.GetValue()[controller_idx].body_color_left;
189 controller.right_color.body_color = Settings::values.players[controller_idx].body_color_right; 192 controller.left_color.button_color =
193 Settings::values.players.GetValue()[controller_idx].button_color_left;
194 controller.right_color.body_color =
195 Settings::values.players.GetValue()[controller_idx].body_color_right;
190 controller.right_color.button_color = 196 controller.right_color.button_color =
191 Settings::values.players[controller_idx].button_color_right; 197 Settings::values.players.GetValue()[controller_idx].button_color_right;
192 198
193 controller.battery_level[0] = BATTERY_FULL; 199 controller.battery_level[0] = BATTERY_FULL;
194 controller.battery_level[1] = BATTERY_FULL; 200 controller.battery_level[1] = BATTERY_FULL;
@@ -199,7 +205,7 @@ void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) {
199 205
200void Controller_NPad::OnInit() { 206void Controller_NPad::OnInit() {
201 auto& kernel = system.Kernel(); 207 auto& kernel = system.Kernel();
202 for (std::size_t i = 0; i < styleset_changed_events.size(); i++) { 208 for (std::size_t i = 0; i < styleset_changed_events.size(); ++i) {
203 styleset_changed_events[i] = Kernel::WritableEvent::CreateEventPair( 209 styleset_changed_events[i] = Kernel::WritableEvent::CreateEventPair(
204 kernel, fmt::format("npad:NpadStyleSetChanged_{}", i)); 210 kernel, fmt::format("npad:NpadStyleSetChanged_{}", i));
205 } 211 }
@@ -208,6 +214,8 @@ void Controller_NPad::OnInit() {
208 return; 214 return;
209 } 215 }
210 216
217 OnLoadInputDevices();
218
211 if (style.raw == 0) { 219 if (style.raw == 0) {
212 // We want to support all controllers 220 // We want to support all controllers
213 style.handheld.Assign(1); 221 style.handheld.Assign(1);
@@ -218,12 +226,27 @@ void Controller_NPad::OnInit() {
218 style.pokeball.Assign(1); 226 style.pokeball.Assign(1);
219 } 227 }
220 228
221 std::transform(Settings::values.players.begin(), Settings::values.players.end(), 229 std::transform(Settings::values.players.GetValue().begin(),
222 connected_controllers.begin(), [](const Settings::PlayerInput& player) { 230 Settings::values.players.GetValue().end(), connected_controllers.begin(),
231 [](const Settings::PlayerInput& player) {
223 return ControllerHolder{MapSettingsTypeToNPad(player.controller_type), 232 return ControllerHolder{MapSettingsTypeToNPad(player.controller_type),
224 player.connected}; 233 player.connected};
225 }); 234 });
226 235
236 // Connect the Player 1 or Handheld controller if none are connected.
237 if (std::none_of(connected_controllers.begin(), connected_controllers.end(),
238 [](const ControllerHolder& controller) { return controller.is_connected; })) {
239 const auto controller =
240 MapSettingsTypeToNPad(Settings::values.players.GetValue()[0].controller_type);
241 if (controller == NPadControllerType::Handheld) {
242 Settings::values.players.GetValue()[HANDHELD_INDEX].connected = true;
243 connected_controllers[HANDHELD_INDEX] = {controller, true};
244 } else {
245 Settings::values.players.GetValue()[0].connected = true;
246 connected_controllers[0] = {controller, true};
247 }
248 }
249
227 // Account for handheld 250 // Account for handheld
228 if (connected_controllers[HANDHELD_INDEX].is_connected) { 251 if (connected_controllers[HANDHELD_INDEX].is_connected) {
229 connected_controllers[HANDHELD_INDEX].type = NPadControllerType::Handheld; 252 connected_controllers[HANDHELD_INDEX].type = NPadControllerType::Handheld;
@@ -242,7 +265,7 @@ void Controller_NPad::OnInit() {
242} 265}
243 266
244void Controller_NPad::OnLoadInputDevices() { 267void Controller_NPad::OnLoadInputDevices() {
245 const auto& players = Settings::values.players; 268 const auto& players = Settings::values.players.GetValue();
246 for (std::size_t i = 0; i < players.size(); ++i) { 269 for (std::size_t i = 0; i < players.size(); ++i) {
247 std::transform(players[i].buttons.begin() + Settings::NativeButton::BUTTON_HID_BEGIN, 270 std::transform(players[i].buttons.begin() + Settings::NativeButton::BUTTON_HID_BEGIN,
248 players[i].buttons.begin() + Settings::NativeButton::BUTTON_HID_END, 271 players[i].buttons.begin() + Settings::NativeButton::BUTTON_HID_END,
@@ -250,13 +273,26 @@ void Controller_NPad::OnLoadInputDevices() {
250 std::transform(players[i].analogs.begin() + Settings::NativeAnalog::STICK_HID_BEGIN, 273 std::transform(players[i].analogs.begin() + Settings::NativeAnalog::STICK_HID_BEGIN,
251 players[i].analogs.begin() + Settings::NativeAnalog::STICK_HID_END, 274 players[i].analogs.begin() + Settings::NativeAnalog::STICK_HID_END,
252 sticks[i].begin(), Input::CreateDevice<Input::AnalogDevice>); 275 sticks[i].begin(), Input::CreateDevice<Input::AnalogDevice>);
276 std::transform(players[i].vibrations.begin() +
277 Settings::NativeVibration::VIBRATION_HID_BEGIN,
278 players[i].vibrations.begin() + Settings::NativeVibration::VIBRATION_HID_END,
279 vibrations[i].begin(), Input::CreateDevice<Input::VibrationDevice>);
253 std::transform(players[i].motions.begin() + Settings::NativeMotion::MOTION_HID_BEGIN, 280 std::transform(players[i].motions.begin() + Settings::NativeMotion::MOTION_HID_BEGIN,
254 players[i].motions.begin() + Settings::NativeMotion::MOTION_HID_END, 281 players[i].motions.begin() + Settings::NativeMotion::MOTION_HID_END,
255 motions[i].begin(), Input::CreateDevice<Input::MotionDevice>); 282 motions[i].begin(), Input::CreateDevice<Input::MotionDevice>);
283 for (std::size_t device_idx = 0; device_idx < vibrations[i].size(); ++device_idx) {
284 InitializeVibrationDeviceAtIndex(i, device_idx);
285 }
256 } 286 }
257} 287}
258 288
259void Controller_NPad::OnRelease() {} 289void Controller_NPad::OnRelease() {
290 for (std::size_t npad_idx = 0; npad_idx < vibrations.size(); ++npad_idx) {
291 for (std::size_t device_idx = 0; device_idx < vibrations[npad_idx].size(); ++device_idx) {
292 VibrateControllerAtIndex(npad_idx, device_idx, {});
293 }
294 }
295}
260 296
261void Controller_NPad::RequestPadStateUpdate(u32 npad_id) { 297void Controller_NPad::RequestPadStateUpdate(u32 npad_id) {
262 const auto controller_idx = NPadIdToIndex(npad_id); 298 const auto controller_idx = NPadIdToIndex(npad_id);
@@ -339,7 +375,7 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
339 if (!IsControllerActivated()) { 375 if (!IsControllerActivated()) {
340 return; 376 return;
341 } 377 }
342 for (std::size_t i = 0; i < shared_memory_entries.size(); i++) { 378 for (std::size_t i = 0; i < shared_memory_entries.size(); ++i) {
343 auto& npad = shared_memory_entries[i]; 379 auto& npad = shared_memory_entries[i];
344 const std::array<NPadGeneric*, 7> controller_npads{&npad.main_controller_states, 380 const std::array<NPadGeneric*, 7> controller_npads{&npad.main_controller_states,
345 &npad.handheld_states, 381 &npad.handheld_states,
@@ -481,7 +517,7 @@ void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing
481 if (!IsControllerActivated()) { 517 if (!IsControllerActivated()) {
482 return; 518 return;
483 } 519 }
484 for (std::size_t i = 0; i < shared_memory_entries.size(); i++) { 520 for (std::size_t i = 0; i < shared_memory_entries.size(); ++i) {
485 auto& npad = shared_memory_entries[i]; 521 auto& npad = shared_memory_entries[i];
486 522
487 const auto& controller_type = connected_controllers[i].type; 523 const auto& controller_type = connected_controllers[i].type;
@@ -515,7 +551,7 @@ void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing
515 // Try to read sixaxis sensor states 551 // Try to read sixaxis sensor states
516 std::array<MotionDevice, 2> motion_devices; 552 std::array<MotionDevice, 2> motion_devices;
517 553
518 if (sixaxis_sensors_enabled && Settings::values.motion_enabled) { 554 if (sixaxis_sensors_enabled && Settings::values.motion_enabled.GetValue()) {
519 sixaxis_at_rest = true; 555 sixaxis_at_rest = true;
520 for (std::size_t e = 0; e < motion_devices.size(); ++e) { 556 for (std::size_t e = 0; e < motion_devices.size(); ++e) {
521 const auto& device = motions[i][e]; 557 const auto& device = motions[i][e];
@@ -601,15 +637,15 @@ void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing
601 shared_memory_entries.size() * sizeof(NPadEntry)); 637 shared_memory_entries.size() * sizeof(NPadEntry));
602} 638}
603 639
604void Controller_NPad::SetSupportedStyleSet(NPadType style_set) { 640void Controller_NPad::SetSupportedStyleSet(NpadStyleSet style_set) {
605 style.raw = style_set.raw; 641 style.raw = style_set.raw;
606} 642}
607 643
608Controller_NPad::NPadType Controller_NPad::GetSupportedStyleSet() const { 644Controller_NPad::NpadStyleSet Controller_NPad::GetSupportedStyleSet() const {
609 return style; 645 return style;
610} 646}
611 647
612void Controller_NPad::SetSupportedNPadIdTypes(u8* data, std::size_t length) { 648void Controller_NPad::SetSupportedNpadIdTypes(u8* data, std::size_t length) {
613 ASSERT(length > 0 && (length % sizeof(u32)) == 0); 649 ASSERT(length > 0 && (length % sizeof(u32)) == 0);
614 supported_npad_id_types.clear(); 650 supported_npad_id_types.clear();
615 supported_npad_id_types.resize(length / sizeof(u32)); 651 supported_npad_id_types.resize(length / sizeof(u32));
@@ -621,7 +657,7 @@ void Controller_NPad::GetSupportedNpadIdTypes(u32* data, std::size_t max_length)
621 std::memcpy(data, supported_npad_id_types.data(), supported_npad_id_types.size()); 657 std::memcpy(data, supported_npad_id_types.data(), supported_npad_id_types.size());
622} 658}
623 659
624std::size_t Controller_NPad::GetSupportedNPadIdTypesSize() const { 660std::size_t Controller_NPad::GetSupportedNpadIdTypesSize() const {
625 return supported_npad_id_types.size(); 661 return supported_npad_id_types.size();
626} 662}
627 663
@@ -641,7 +677,7 @@ Controller_NPad::NpadHandheldActivationMode Controller_NPad::GetNpadHandheldActi
641 return handheld_activation_mode; 677 return handheld_activation_mode;
642} 678}
643 679
644void Controller_NPad::SetNpadMode(u32 npad_id, NPadAssignments assignment_mode) { 680void Controller_NPad::SetNpadMode(u32 npad_id, NpadAssignments assignment_mode) {
645 const std::size_t npad_index = NPadIdToIndex(npad_id); 681 const std::size_t npad_index = NPadIdToIndex(npad_id);
646 ASSERT(npad_index < shared_memory_entries.size()); 682 ASSERT(npad_index < shared_memory_entries.size());
647 if (shared_memory_entries[npad_index].pad_assignment != assignment_mode) { 683 if (shared_memory_entries[npad_index].pad_assignment != assignment_mode) {
@@ -649,35 +685,140 @@ void Controller_NPad::SetNpadMode(u32 npad_id, NPadAssignments assignment_mode)
649 } 685 }
650} 686}
651 687
652void Controller_NPad::VibrateController(const std::vector<u32>& controllers, 688bool Controller_NPad::VibrateControllerAtIndex(std::size_t npad_index, std::size_t device_index,
653 const std::vector<Vibration>& vibrations) { 689 const VibrationValue& vibration_value) {
654 LOG_TRACE(Service_HID, "called"); 690 if (!connected_controllers[npad_index].is_connected || !vibrations[npad_index][device_index]) {
655 691 return false;
656 if (!Settings::values.vibration_enabled || !can_controllers_vibrate) {
657 return;
658 } 692 }
659 bool success = true; 693
660 for (std::size_t i = 0; i < controllers.size(); ++i) { 694 const auto& player = Settings::values.players.GetValue()[npad_index];
661 if (!connected_controllers[i].is_connected) { 695
662 continue; 696 if (!player.vibration_enabled) {
697 if (latest_vibration_values[npad_index][device_index].amp_low != 0.0f ||
698 latest_vibration_values[npad_index][device_index].amp_high != 0.0f) {
699 // Send an empty vibration to stop any vibrations.
700 vibrations[npad_index][device_index]->SetRumblePlay(0.0f, 160.0f, 0.0f, 320.0f);
701 // Then reset the vibration value to its default value.
702 latest_vibration_values[npad_index][device_index] = {};
663 } 703 }
664 using namespace Settings::NativeButton; 704
665 const auto& button_state = buttons[i]; 705 return false;
666 if (button_state[A - BUTTON_HID_BEGIN]) { 706 }
667 if (button_state[A - BUTTON_HID_BEGIN]->SetRumblePlay( 707
668 vibrations[0].amp_high, vibrations[0].amp_low, vibrations[0].freq_high, 708 if (!Settings::values.enable_accurate_vibrations.GetValue()) {
669 vibrations[0].freq_low)) { 709 using std::chrono::duration_cast;
670 success = false; 710 using std::chrono::milliseconds;
671 } 711 using std::chrono::steady_clock;
712
713 const auto now = steady_clock::now();
714
715 // Filter out non-zero vibrations that are within 10ms of each other.
716 if ((vibration_value.amp_low != 0.0f || vibration_value.amp_high != 0.0f) &&
717 duration_cast<milliseconds>(now - last_vibration_timepoints[npad_index][device_index]) <
718 milliseconds(10)) {
719 return false;
672 } 720 }
721
722 last_vibration_timepoints[npad_index][device_index] = now;
723 }
724
725 auto& vibration = vibrations[npad_index][device_index];
726 const auto player_vibration_strength = static_cast<f32>(player.vibration_strength);
727 const auto amp_low =
728 std::min(vibration_value.amp_low * player_vibration_strength / 100.0f, 1.0f);
729 const auto amp_high =
730 std::min(vibration_value.amp_high * player_vibration_strength / 100.0f, 1.0f);
731 return vibration->SetRumblePlay(amp_low, vibration_value.freq_low, amp_high,
732 vibration_value.freq_high);
733}
734
735void Controller_NPad::VibrateController(const DeviceHandle& vibration_device_handle,
736 const VibrationValue& vibration_value) {
737 if (!Settings::values.vibration_enabled.GetValue() && !permit_vibration_session_enabled) {
738 return;
739 }
740
741 const auto npad_index = NPadIdToIndex(vibration_device_handle.npad_id);
742 const auto device_index = static_cast<std::size_t>(vibration_device_handle.device_index);
743
744 if (!vibration_devices_mounted[npad_index][device_index] ||
745 !connected_controllers[npad_index].is_connected) {
746 return;
673 } 747 }
674 if (success) { 748
675 last_processed_vibration = vibrations.back(); 749 if (vibration_device_handle.device_index == DeviceIndex::None) {
750 UNREACHABLE_MSG("DeviceIndex should never be None!");
751 return;
752 }
753
754 // Some games try to send mismatched parameters in the device handle, block these.
755 if ((connected_controllers[npad_index].type == NPadControllerType::JoyLeft &&
756 (vibration_device_handle.npad_type == NpadType::JoyconRight ||
757 vibration_device_handle.device_index == DeviceIndex::Right)) ||
758 (connected_controllers[npad_index].type == NPadControllerType::JoyRight &&
759 (vibration_device_handle.npad_type == NpadType::JoyconLeft ||
760 vibration_device_handle.device_index == DeviceIndex::Left))) {
761 return;
762 }
763
764 // Filter out vibrations with equivalent values to reduce unnecessary state changes.
765 if (vibration_value.amp_low == latest_vibration_values[npad_index][device_index].amp_low &&
766 vibration_value.amp_high == latest_vibration_values[npad_index][device_index].amp_high) {
767 return;
768 }
769
770 if (VibrateControllerAtIndex(npad_index, device_index, vibration_value)) {
771 latest_vibration_values[npad_index][device_index] = vibration_value;
676 } 772 }
677} 773}
678 774
679Controller_NPad::Vibration Controller_NPad::GetLastVibration() const { 775void Controller_NPad::VibrateControllers(const std::vector<DeviceHandle>& vibration_device_handles,
680 return last_processed_vibration; 776 const std::vector<VibrationValue>& vibration_values) {
777 if (!Settings::values.vibration_enabled.GetValue() && !permit_vibration_session_enabled) {
778 return;
779 }
780
781 ASSERT_OR_EXECUTE_MSG(
782 vibration_device_handles.size() == vibration_values.size(), { return; },
783 "The amount of device handles does not match with the amount of vibration values,"
784 "this is undefined behavior!");
785
786 for (std::size_t i = 0; i < vibration_device_handles.size(); ++i) {
787 VibrateController(vibration_device_handles[i], vibration_values[i]);
788 }
789}
790
791Controller_NPad::VibrationValue Controller_NPad::GetLastVibration(
792 const DeviceHandle& vibration_device_handle) const {
793 const auto npad_index = NPadIdToIndex(vibration_device_handle.npad_id);
794 const auto device_index = static_cast<std::size_t>(vibration_device_handle.device_index);
795 return latest_vibration_values[npad_index][device_index];
796}
797
798void Controller_NPad::InitializeVibrationDevice(const DeviceHandle& vibration_device_handle) {
799 const auto npad_index = NPadIdToIndex(vibration_device_handle.npad_id);
800 const auto device_index = static_cast<std::size_t>(vibration_device_handle.device_index);
801 InitializeVibrationDeviceAtIndex(npad_index, device_index);
802}
803
804void Controller_NPad::InitializeVibrationDeviceAtIndex(std::size_t npad_index,
805 std::size_t device_index) {
806 if (vibrations[npad_index][device_index]) {
807 vibration_devices_mounted[npad_index][device_index] =
808 vibrations[npad_index][device_index]->GetStatus() == 1;
809 } else {
810 vibration_devices_mounted[npad_index][device_index] = false;
811 }
812}
813
814void Controller_NPad::SetPermitVibrationSession(bool permit_vibration_session) {
815 permit_vibration_session_enabled = permit_vibration_session;
816}
817
818bool Controller_NPad::IsVibrationDeviceMounted(const DeviceHandle& vibration_device_handle) const {
819 const auto npad_index = NPadIdToIndex(vibration_device_handle.npad_id);
820 const auto device_index = static_cast<std::size_t>(vibration_device_handle.device_index);
821 return vibration_devices_mounted[npad_index][device_index];
681} 822}
682 823
683std::shared_ptr<Kernel::ReadableEvent> Controller_NPad::GetStyleSetChangedEvent(u32 npad_id) const { 824std::shared_ptr<Kernel::ReadableEvent> Controller_NPad::GetStyleSetChangedEvent(u32 npad_id) const {
@@ -696,31 +837,38 @@ void Controller_NPad::AddNewControllerAt(NPadControllerType controller, std::siz
696void Controller_NPad::UpdateControllerAt(NPadControllerType controller, std::size_t npad_index, 837void Controller_NPad::UpdateControllerAt(NPadControllerType controller, std::size_t npad_index,
697 bool connected) { 838 bool connected) {
698 if (!connected) { 839 if (!connected) {
699 DisconnectNPadAtIndex(npad_index); 840 DisconnectNpadAtIndex(npad_index);
700 return; 841 return;
701 } 842 }
702 843
703 if (controller == NPadControllerType::Handheld) { 844 if (controller == NPadControllerType::Handheld) {
704 Settings::values.players[HANDHELD_INDEX].controller_type = 845 Settings::values.players.GetValue()[HANDHELD_INDEX].controller_type =
705 MapNPadToSettingsType(controller); 846 MapNPadToSettingsType(controller);
706 Settings::values.players[HANDHELD_INDEX].connected = true; 847 Settings::values.players.GetValue()[HANDHELD_INDEX].connected = true;
707 connected_controllers[HANDHELD_INDEX] = {controller, true}; 848 connected_controllers[HANDHELD_INDEX] = {controller, true};
708 InitNewlyAddedController(HANDHELD_INDEX); 849 InitNewlyAddedController(HANDHELD_INDEX);
709 return; 850 return;
710 } 851 }
711 852
712 Settings::values.players[npad_index].controller_type = MapNPadToSettingsType(controller); 853 Settings::values.players.GetValue()[npad_index].controller_type =
713 Settings::values.players[npad_index].connected = true; 854 MapNPadToSettingsType(controller);
855 Settings::values.players.GetValue()[npad_index].connected = true;
714 connected_controllers[npad_index] = {controller, true}; 856 connected_controllers[npad_index] = {controller, true};
715 InitNewlyAddedController(npad_index); 857 InitNewlyAddedController(npad_index);
716} 858}
717 859
718void Controller_NPad::DisconnectNPad(u32 npad_id) { 860void Controller_NPad::DisconnectNpad(u32 npad_id) {
719 DisconnectNPadAtIndex(NPadIdToIndex(npad_id)); 861 DisconnectNpadAtIndex(NPadIdToIndex(npad_id));
720} 862}
721 863
722void Controller_NPad::DisconnectNPadAtIndex(std::size_t npad_index) { 864void Controller_NPad::DisconnectNpadAtIndex(std::size_t npad_index) {
723 Settings::values.players[npad_index].connected = false; 865 for (std::size_t device_idx = 0; device_idx < vibrations[npad_index].size(); ++device_idx) {
866 // Send an empty vibration to stop any vibrations.
867 VibrateControllerAtIndex(npad_index, device_idx, {});
868 vibration_devices_mounted[npad_index][device_idx] = false;
869 }
870
871 Settings::values.players.GetValue()[npad_index].connected = false;
724 connected_controllers[npad_index].is_connected = false; 872 connected_controllers[npad_index].is_connected = false;
725 873
726 auto& controller = shared_memory_entries[npad_index]; 874 auto& controller = shared_memory_entries[npad_index];
@@ -758,7 +906,7 @@ void Controller_NPad::MergeSingleJoyAsDualJoy(u32 npad_id_1, u32 npad_id_2) {
758 (connected_controllers[npad_index_2].type == NPadControllerType::JoyLeft && 906 (connected_controllers[npad_index_2].type == NPadControllerType::JoyLeft &&
759 connected_controllers[npad_index_1].type == NPadControllerType::JoyRight)) { 907 connected_controllers[npad_index_1].type == NPadControllerType::JoyRight)) {
760 // Disconnect the joycon at the second id and connect the dual joycon at the first index. 908 // Disconnect the joycon at the second id and connect the dual joycon at the first index.
761 DisconnectNPad(npad_id_2); 909 DisconnectNpad(npad_id_2);
762 AddNewControllerAt(NPadControllerType::JoyDual, npad_index_1); 910 AddNewControllerAt(NPadControllerType::JoyDual, npad_index_1);
763 } 911 }
764} 912}
@@ -830,14 +978,6 @@ void Controller_NPad::SetUnintendedHomeButtonInputProtectionEnabled(bool is_prot
830 unintended_home_button_input_protection[NPadIdToIndex(npad_id)] = is_protection_enabled; 978 unintended_home_button_input_protection[NPadIdToIndex(npad_id)] = is_protection_enabled;
831} 979}
832 980
833void Controller_NPad::SetVibrationEnabled(bool can_vibrate) {
834 can_controllers_vibrate = can_vibrate;
835}
836
837bool Controller_NPad::IsVibrationEnabled() const {
838 return can_controllers_vibrate;
839}
840
841void Controller_NPad::ClearAllConnectedControllers() { 981void Controller_NPad::ClearAllConnectedControllers() {
842 for (auto& controller : connected_controllers) { 982 for (auto& controller : connected_controllers) {
843 if (controller.is_connected && controller.type != NPadControllerType::None) { 983 if (controller.is_connected && controller.type != NPadControllerType::None) {
@@ -882,7 +1022,7 @@ bool Controller_NPad::IsControllerSupported(NPadControllerType controller) const
882 return false; 1022 return false;
883 } 1023 }
884 // Handheld should not be supported in docked mode 1024 // Handheld should not be supported in docked mode
885 if (Settings::values.use_docked_mode) { 1025 if (Settings::values.use_docked_mode.GetValue()) {
886 return false; 1026 return false;
887 } 1027 }
888 1028
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h
index fd5c5a6eb..160dcbbe3 100644
--- a/src/core/hle/service/hid/controllers/npad.h
+++ b/src/core/hle/service/hid/controllers/npad.h
@@ -39,28 +39,30 @@ public:
39 // Called when input devices should be loaded 39 // Called when input devices should be loaded
40 void OnLoadInputDevices() override; 40 void OnLoadInputDevices() override;
41 41
42 struct NPadType { 42 enum class NPadControllerType {
43 union { 43 None,
44 u32_le raw{}; 44 ProController,
45 45 Handheld,
46 BitField<0, 1, u32> pro_controller; 46 JoyDual,
47 BitField<1, 1, u32> handheld; 47 JoyLeft,
48 BitField<2, 1, u32> joycon_dual; 48 JoyRight,
49 BitField<3, 1, u32> joycon_left; 49 Pokeball,
50 BitField<4, 1, u32> joycon_right; 50 };
51 51
52 BitField<6, 1, u32> pokeball; // TODO(ogniK): Confirm when possible 52 enum class NpadType : u8 {
53 }; 53 ProController = 3,
54 Handheld = 4,
55 JoyconDual = 5,
56 JoyconLeft = 6,
57 JoyconRight = 7,
58 Pokeball = 9,
54 }; 59 };
55 static_assert(sizeof(NPadType) == 4, "NPadType is an invalid size");
56 60
57 struct Vibration { 61 enum class DeviceIndex : u8 {
58 f32 amp_low; 62 Left = 0,
59 f32 freq_low; 63 Right = 1,
60 f32 amp_high; 64 None = 2,
61 f32 freq_high;
62 }; 65 };
63 static_assert(sizeof(Vibration) == 0x10, "Vibration is an invalid size");
64 66
65 enum class GyroscopeZeroDriftMode : u32 { 67 enum class GyroscopeZeroDriftMode : u32 {
66 Loose = 0, 68 Loose = 0,
@@ -73,7 +75,7 @@ public:
73 Horizontal = 1, 75 Horizontal = 1,
74 }; 76 };
75 77
76 enum class NPadAssignments : u32_le { 78 enum class NpadAssignments : u32 {
77 Dual = 0, 79 Dual = 0,
78 Single = 1, 80 Single = 1,
79 }; 81 };
@@ -84,15 +86,36 @@ public:
84 None = 2, 86 None = 2,
85 }; 87 };
86 88
87 enum class NPadControllerType { 89 struct DeviceHandle {
88 None, 90 NpadType npad_type{};
89 ProController, 91 u8 npad_id{};
90 Handheld, 92 DeviceIndex device_index{};
91 JoyDual, 93 INSERT_PADDING_BYTES(1);
92 JoyLeft, 94 };
93 JoyRight, 95 static_assert(sizeof(DeviceHandle) == 4, "DeviceHandle is an invalid size");
94 Pokeball, 96
97 struct NpadStyleSet {
98 union {
99 u32_le raw{};
100
101 BitField<0, 1, u32> pro_controller;
102 BitField<1, 1, u32> handheld;
103 BitField<2, 1, u32> joycon_dual;
104 BitField<3, 1, u32> joycon_left;
105 BitField<4, 1, u32> joycon_right;
106
107 BitField<6, 1, u32> pokeball; // TODO(ogniK): Confirm when possible
108 };
109 };
110 static_assert(sizeof(NpadStyleSet) == 4, "NpadStyleSet is an invalid size");
111
112 struct VibrationValue {
113 f32 amp_low{0.0f};
114 f32 freq_low{160.0f};
115 f32 amp_high{0.0f};
116 f32 freq_high{320.0f};
95 }; 117 };
118 static_assert(sizeof(VibrationValue) == 0x10, "Vibration is an invalid size");
96 119
97 struct LedPattern { 120 struct LedPattern {
98 explicit LedPattern(u64 light1, u64 light2, u64 light3, u64 light4) { 121 explicit LedPattern(u64 light1, u64 light2, u64 light3, u64 light4) {
@@ -110,12 +133,12 @@ public:
110 }; 133 };
111 }; 134 };
112 135
113 void SetSupportedStyleSet(NPadType style_set); 136 void SetSupportedStyleSet(NpadStyleSet style_set);
114 NPadType GetSupportedStyleSet() const; 137 NpadStyleSet GetSupportedStyleSet() const;
115 138
116 void SetSupportedNPadIdTypes(u8* data, std::size_t length); 139 void SetSupportedNpadIdTypes(u8* data, std::size_t length);
117 void GetSupportedNpadIdTypes(u32* data, std::size_t max_length); 140 void GetSupportedNpadIdTypes(u32* data, std::size_t max_length);
118 std::size_t GetSupportedNPadIdTypesSize() const; 141 std::size_t GetSupportedNpadIdTypesSize() const;
119 142
120 void SetHoldType(NpadHoldType joy_hold_type); 143 void SetHoldType(NpadHoldType joy_hold_type);
121 NpadHoldType GetHoldType() const; 144 NpadHoldType GetHoldType() const;
@@ -123,12 +146,26 @@ public:
123 void SetNpadHandheldActivationMode(NpadHandheldActivationMode activation_mode); 146 void SetNpadHandheldActivationMode(NpadHandheldActivationMode activation_mode);
124 NpadHandheldActivationMode GetNpadHandheldActivationMode() const; 147 NpadHandheldActivationMode GetNpadHandheldActivationMode() const;
125 148
126 void SetNpadMode(u32 npad_id, NPadAssignments assignment_mode); 149 void SetNpadMode(u32 npad_id, NpadAssignments assignment_mode);
150
151 bool VibrateControllerAtIndex(std::size_t npad_index, std::size_t device_index,
152 const VibrationValue& vibration_value);
153
154 void VibrateController(const DeviceHandle& vibration_device_handle,
155 const VibrationValue& vibration_value);
156
157 void VibrateControllers(const std::vector<DeviceHandle>& vibration_device_handles,
158 const std::vector<VibrationValue>& vibration_values);
159
160 VibrationValue GetLastVibration(const DeviceHandle& vibration_device_handle) const;
161
162 void InitializeVibrationDevice(const DeviceHandle& vibration_device_handle);
163
164 void InitializeVibrationDeviceAtIndex(std::size_t npad_index, std::size_t device_index);
127 165
128 void VibrateController(const std::vector<u32>& controllers, 166 void SetPermitVibrationSession(bool permit_vibration_session);
129 const std::vector<Vibration>& vibrations);
130 167
131 Vibration GetLastVibration() const; 168 bool IsVibrationDeviceMounted(const DeviceHandle& vibration_device_handle) const;
132 169
133 std::shared_ptr<Kernel::ReadableEvent> GetStyleSetChangedEvent(u32 npad_id) const; 170 std::shared_ptr<Kernel::ReadableEvent> GetStyleSetChangedEvent(u32 npad_id) const;
134 void SignalStyleSetChangedEvent(u32 npad_id) const; 171 void SignalStyleSetChangedEvent(u32 npad_id) const;
@@ -138,8 +175,8 @@ public:
138 // Adds a new controller at an index with connection status. 175 // Adds a new controller at an index with connection status.
139 void UpdateControllerAt(NPadControllerType controller, std::size_t npad_index, bool connected); 176 void UpdateControllerAt(NPadControllerType controller, std::size_t npad_index, bool connected);
140 177
141 void DisconnectNPad(u32 npad_id); 178 void DisconnectNpad(u32 npad_id);
142 void DisconnectNPadAtIndex(std::size_t index); 179 void DisconnectNpadAtIndex(std::size_t index);
143 180
144 void SetGyroscopeZeroDriftMode(GyroscopeZeroDriftMode drift_mode); 181 void SetGyroscopeZeroDriftMode(GyroscopeZeroDriftMode drift_mode);
145 GyroscopeZeroDriftMode GetGyroscopeZeroDriftMode() const; 182 GyroscopeZeroDriftMode GetGyroscopeZeroDriftMode() const;
@@ -148,8 +185,6 @@ public:
148 LedPattern GetLedPattern(u32 npad_id); 185 LedPattern GetLedPattern(u32 npad_id);
149 bool IsUnintendedHomeButtonInputProtectionEnabled(u32 npad_id) const; 186 bool IsUnintendedHomeButtonInputProtectionEnabled(u32 npad_id) const;
150 void SetUnintendedHomeButtonInputProtectionEnabled(bool is_protection_enabled, u32 npad_id); 187 void SetUnintendedHomeButtonInputProtectionEnabled(bool is_protection_enabled, u32 npad_id);
151 void SetVibrationEnabled(bool can_vibrate);
152 bool IsVibrationEnabled() const;
153 void ClearAllConnectedControllers(); 188 void ClearAllConnectedControllers();
154 void DisconnectAllConnectedControllers(); 189 void DisconnectAllConnectedControllers();
155 void ConnectAllDisconnectedControllers(); 190 void ConnectAllDisconnectedControllers();
@@ -324,8 +359,8 @@ private:
324 }; 359 };
325 360
326 struct NPadEntry { 361 struct NPadEntry {
327 NPadType joy_styles; 362 NpadStyleSet joy_styles;
328 NPadAssignments pad_assignment; 363 NpadAssignments pad_assignment;
329 364
330 ColorReadError single_color_error; 365 ColorReadError single_color_error;
331 ControllerColor single_color; 366 ControllerColor single_color;
@@ -368,7 +403,7 @@ private:
368 403
369 u32 press_state{}; 404 u32 press_state{};
370 405
371 NPadType style{}; 406 NpadStyleSet style{};
372 std::array<NPadEntry, 10> shared_memory_entries{}; 407 std::array<NPadEntry, 10> shared_memory_entries{};
373 using ButtonArray = std::array< 408 using ButtonArray = std::array<
374 std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeButton::NUM_BUTTONS_HID>, 409 std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeButton::NUM_BUTTONS_HID>,
@@ -376,22 +411,28 @@ private:
376 using StickArray = std::array< 411 using StickArray = std::array<
377 std::array<std::unique_ptr<Input::AnalogDevice>, Settings::NativeAnalog::NUM_STICKS_HID>, 412 std::array<std::unique_ptr<Input::AnalogDevice>, Settings::NativeAnalog::NUM_STICKS_HID>,
378 10>; 413 10>;
414 using VibrationArray = std::array<std::array<std::unique_ptr<Input::VibrationDevice>,
415 Settings::NativeVibration::NUM_VIBRATIONS_HID>,
416 10>;
379 using MotionArray = std::array< 417 using MotionArray = std::array<
380 std::array<std::unique_ptr<Input::MotionDevice>, Settings::NativeMotion::NUM_MOTION_HID>, 418 std::array<std::unique_ptr<Input::MotionDevice>, Settings::NativeMotion::NUM_MOTIONS_HID>,
381 10>; 419 10>;
382 ButtonArray buttons; 420 ButtonArray buttons;
383 StickArray sticks; 421 StickArray sticks;
422 VibrationArray vibrations;
384 MotionArray motions; 423 MotionArray motions;
385 std::vector<u32> supported_npad_id_types{}; 424 std::vector<u32> supported_npad_id_types{};
386 NpadHoldType hold_type{NpadHoldType::Vertical}; 425 NpadHoldType hold_type{NpadHoldType::Vertical};
387 NpadHandheldActivationMode handheld_activation_mode{NpadHandheldActivationMode::Dual}; 426 NpadHandheldActivationMode handheld_activation_mode{NpadHandheldActivationMode::Dual};
388 // Each controller should have their own styleset changed event 427 // Each controller should have their own styleset changed event
389 std::array<Kernel::EventPair, 10> styleset_changed_events; 428 std::array<Kernel::EventPair, 10> styleset_changed_events;
390 Vibration last_processed_vibration{}; 429 std::array<std::array<std::chrono::steady_clock::time_point, 2>, 10> last_vibration_timepoints;
430 std::array<std::array<VibrationValue, 2>, 10> latest_vibration_values{};
431 bool permit_vibration_session_enabled{false};
432 std::array<std::array<bool, 2>, 10> vibration_devices_mounted{};
391 std::array<ControllerHolder, 10> connected_controllers{}; 433 std::array<ControllerHolder, 10> connected_controllers{};
392 std::array<bool, 10> unintended_home_button_input_protection{}; 434 std::array<bool, 10> unintended_home_button_input_protection{};
393 GyroscopeZeroDriftMode gyroscope_zero_drift_mode{GyroscopeZeroDriftMode::Standard}; 435 GyroscopeZeroDriftMode gyroscope_zero_drift_mode{GyroscopeZeroDriftMode::Standard};
394 bool can_controllers_vibrate{true};
395 bool sixaxis_sensors_enabled{true}; 436 bool sixaxis_sensors_enabled{true};
396 bool sixaxis_at_rest{true}; 437 bool sixaxis_at_rest{true};
397 std::array<ControllerPad, 10> npad_pad_states{}; 438 std::array<ControllerPad, 10> npad_pad_states{};
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 50f709b25..902516b29 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -139,20 +139,34 @@ void IAppletResource::UpdateMotion(std::uintptr_t user_data, std::chrono::nanose
139 139
140class IActiveVibrationDeviceList final : public ServiceFramework<IActiveVibrationDeviceList> { 140class IActiveVibrationDeviceList final : public ServiceFramework<IActiveVibrationDeviceList> {
141public: 141public:
142 IActiveVibrationDeviceList() : ServiceFramework("IActiveVibrationDeviceList") { 142 explicit IActiveVibrationDeviceList(std::shared_ptr<IAppletResource> applet_resource_)
143 : ServiceFramework("IActiveVibrationDeviceList"), applet_resource(applet_resource_) {
144 // clang-format off
143 static const FunctionInfo functions[] = { 145 static const FunctionInfo functions[] = {
144 {0, &IActiveVibrationDeviceList::ActivateVibrationDevice, "ActivateVibrationDevice"}, 146 {0, &IActiveVibrationDeviceList::InitializeVibrationDevice, "InitializeVibrationDevice"},
145 }; 147 };
148 // clang-format on
149
146 RegisterHandlers(functions); 150 RegisterHandlers(functions);
147 } 151 }
148 152
149private: 153private:
150 void ActivateVibrationDevice(Kernel::HLERequestContext& ctx) { 154 void InitializeVibrationDevice(Kernel::HLERequestContext& ctx) {
151 LOG_WARNING(Service_HID, "(STUBBED) called"); 155 IPC::RequestParser rp{ctx};
156 const auto vibration_device_handle{rp.PopRaw<Controller_NPad::DeviceHandle>()};
157
158 applet_resource->GetController<Controller_NPad>(HidController::NPad)
159 .InitializeVibrationDevice(vibration_device_handle);
160
161 LOG_DEBUG(Service_HID, "called, npad_type={}, npad_id={}, device_index={}",
162 vibration_device_handle.npad_type, vibration_device_handle.npad_id,
163 vibration_device_handle.device_index);
152 164
153 IPC::ResponseBuilder rb{ctx, 2}; 165 IPC::ResponseBuilder rb{ctx, 2};
154 rb.Push(RESULT_SUCCESS); 166 rb.Push(RESULT_SUCCESS);
155 } 167 }
168
169 std::shared_ptr<IAppletResource> applet_resource;
156}; 170};
157 171
158std::shared_ptr<IAppletResource> Hid::GetAppletResource() { 172std::shared_ptr<IAppletResource> Hid::GetAppletResource() {
@@ -241,7 +255,7 @@ Hid::Hid(Core::System& system) : ServiceFramework("hid"), system(system) {
241 {208, nullptr, "GetActualVibrationGcErmCommand"}, 255 {208, nullptr, "GetActualVibrationGcErmCommand"},
242 {209, &Hid::BeginPermitVibrationSession, "BeginPermitVibrationSession"}, 256 {209, &Hid::BeginPermitVibrationSession, "BeginPermitVibrationSession"},
243 {210, &Hid::EndPermitVibrationSession, "EndPermitVibrationSession"}, 257 {210, &Hid::EndPermitVibrationSession, "EndPermitVibrationSession"},
244 {211, nullptr, "IsVibrationDeviceMounted"}, 258 {211, &Hid::IsVibrationDeviceMounted, "IsVibrationDeviceMounted"},
245 {300, &Hid::ActivateConsoleSixAxisSensor, "ActivateConsoleSixAxisSensor"}, 259 {300, &Hid::ActivateConsoleSixAxisSensor, "ActivateConsoleSixAxisSensor"},
246 {301, &Hid::StartConsoleSixAxisSensor, "StartConsoleSixAxisSensor"}, 260 {301, &Hid::StartConsoleSixAxisSensor, "StartConsoleSixAxisSensor"},
247 {302, &Hid::StopConsoleSixAxisSensor, "StopConsoleSixAxisSensor"}, 261 {302, &Hid::StopConsoleSixAxisSensor, "StopConsoleSixAxisSensor"},
@@ -320,142 +334,152 @@ void Hid::CreateAppletResource(Kernel::HLERequestContext& ctx) {
320 rb.PushIpcInterface<IAppletResource>(applet_resource); 334 rb.PushIpcInterface<IAppletResource>(applet_resource);
321} 335}
322 336
323void Hid::ActivateXpad(Kernel::HLERequestContext& ctx) { 337void Hid::ActivateDebugPad(Kernel::HLERequestContext& ctx) {
324 IPC::RequestParser rp{ctx}; 338 IPC::RequestParser rp{ctx};
325 const auto basic_xpad_id{rp.Pop<u32>()};
326 const auto applet_resource_user_id{rp.Pop<u64>()}; 339 const auto applet_resource_user_id{rp.Pop<u64>()};
327 340
328 LOG_DEBUG(Service_HID, "called, basic_xpad_id={}, applet_resource_user_id={}", basic_xpad_id, 341 applet_resource->ActivateController(HidController::DebugPad);
329 applet_resource_user_id); 342
343 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
330 344
331 applet_resource->ActivateController(HidController::XPad);
332 IPC::ResponseBuilder rb{ctx, 2}; 345 IPC::ResponseBuilder rb{ctx, 2};
333 rb.Push(RESULT_SUCCESS); 346 rb.Push(RESULT_SUCCESS);
334} 347}
335 348
336void Hid::GetXpadIDs(Kernel::HLERequestContext& ctx) { 349void Hid::ActivateTouchScreen(Kernel::HLERequestContext& ctx) {
337 IPC::RequestParser rp{ctx}; 350 IPC::RequestParser rp{ctx};
338 const auto applet_resource_user_id{rp.Pop<u64>()}; 351 const auto applet_resource_user_id{rp.Pop<u64>()};
339 352
340 LOG_DEBUG(Service_HID, "(STUBBED) called, applet_resource_user_id={}", applet_resource_user_id); 353 applet_resource->ActivateController(HidController::Touchscreen);
341
342 IPC::ResponseBuilder rb{ctx, 3};
343 rb.Push(RESULT_SUCCESS);
344 rb.Push(0);
345}
346 354
347void Hid::ActivateSixAxisSensor(Kernel::HLERequestContext& ctx) { 355 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
348 IPC::RequestParser rp{ctx};
349 const auto handle{rp.Pop<u32>()};
350 const auto applet_resource_user_id{rp.Pop<u64>()};
351 applet_resource->GetController<Controller_NPad>(HidController::NPad).SetSixAxisEnabled(true);
352 LOG_DEBUG(Service_HID, "called, handle={}, applet_resource_user_id={}", handle,
353 applet_resource_user_id);
354 356
355 IPC::ResponseBuilder rb{ctx, 2}; 357 IPC::ResponseBuilder rb{ctx, 2};
356 rb.Push(RESULT_SUCCESS); 358 rb.Push(RESULT_SUCCESS);
357} 359}
358 360
359void Hid::DeactivateSixAxisSensor(Kernel::HLERequestContext& ctx) { 361void Hid::ActivateMouse(Kernel::HLERequestContext& ctx) {
360 IPC::RequestParser rp{ctx}; 362 IPC::RequestParser rp{ctx};
361 const auto handle{rp.Pop<u32>()};
362 const auto applet_resource_user_id{rp.Pop<u64>()}; 363 const auto applet_resource_user_id{rp.Pop<u64>()};
363 applet_resource->GetController<Controller_NPad>(HidController::NPad).SetSixAxisEnabled(false);
364 364
365 LOG_DEBUG(Service_HID, "called, handle={}, applet_resource_user_id={}", handle, 365 applet_resource->ActivateController(HidController::Mouse);
366 applet_resource_user_id); 366
367 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
367 368
368 IPC::ResponseBuilder rb{ctx, 2}; 369 IPC::ResponseBuilder rb{ctx, 2};
369 rb.Push(RESULT_SUCCESS); 370 rb.Push(RESULT_SUCCESS);
370} 371}
371 372
372void Hid::ActivateDebugPad(Kernel::HLERequestContext& ctx) { 373void Hid::ActivateKeyboard(Kernel::HLERequestContext& ctx) {
373 IPC::RequestParser rp{ctx}; 374 IPC::RequestParser rp{ctx};
374 const auto applet_resource_user_id{rp.Pop<u64>()}; 375 const auto applet_resource_user_id{rp.Pop<u64>()};
375 376
377 applet_resource->ActivateController(HidController::Keyboard);
378
376 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); 379 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
377 380
378 applet_resource->ActivateController(HidController::DebugPad);
379 IPC::ResponseBuilder rb{ctx, 2}; 381 IPC::ResponseBuilder rb{ctx, 2};
380 rb.Push(RESULT_SUCCESS); 382 rb.Push(RESULT_SUCCESS);
381} 383}
382 384
383void Hid::ActivateTouchScreen(Kernel::HLERequestContext& ctx) { 385void Hid::SendKeyboardLockKeyEvent(Kernel::HLERequestContext& ctx) {
384 IPC::RequestParser rp{ctx}; 386 IPC::RequestParser rp{ctx};
385 const auto applet_resource_user_id{rp.Pop<u64>()}; 387 const auto flags{rp.Pop<u32>()};
386 388
387 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); 389 LOG_WARNING(Service_HID, "(STUBBED) called. flags={}", flags);
388 390
389 applet_resource->ActivateController(HidController::Touchscreen);
390 IPC::ResponseBuilder rb{ctx, 2}; 391 IPC::ResponseBuilder rb{ctx, 2};
391 rb.Push(RESULT_SUCCESS); 392 rb.Push(RESULT_SUCCESS);
392} 393}
393 394
394void Hid::ActivateMouse(Kernel::HLERequestContext& ctx) { 395void Hid::ActivateXpad(Kernel::HLERequestContext& ctx) {
395 IPC::RequestParser rp{ctx}; 396 IPC::RequestParser rp{ctx};
396 const auto applet_resource_user_id{rp.Pop<u64>()}; 397 struct Parameters {
398 u32 basic_xpad_id{};
399 INSERT_PADDING_WORDS(1);
400 u64 applet_resource_user_id{};
401 };
397 402
398 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); 403 const auto parameters{rp.PopRaw<Parameters>()};
404
405 applet_resource->ActivateController(HidController::XPad);
406
407 LOG_DEBUG(Service_HID, "called, basic_xpad_id={}, applet_resource_user_id={}",
408 parameters.basic_xpad_id, parameters.applet_resource_user_id);
399 409
400 applet_resource->ActivateController(HidController::Mouse);
401 IPC::ResponseBuilder rb{ctx, 2}; 410 IPC::ResponseBuilder rb{ctx, 2};
402 rb.Push(RESULT_SUCCESS); 411 rb.Push(RESULT_SUCCESS);
403} 412}
404 413
405void Hid::ActivateKeyboard(Kernel::HLERequestContext& ctx) { 414void Hid::GetXpadIDs(Kernel::HLERequestContext& ctx) {
406 IPC::RequestParser rp{ctx}; 415 IPC::RequestParser rp{ctx};
407 const auto applet_resource_user_id{rp.Pop<u64>()}; 416 const auto applet_resource_user_id{rp.Pop<u64>()};
408 417
409 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); 418 LOG_DEBUG(Service_HID, "(STUBBED) called, applet_resource_user_id={}", applet_resource_user_id);
410 419
411 applet_resource->ActivateController(HidController::Keyboard); 420 IPC::ResponseBuilder rb{ctx, 3};
412 IPC::ResponseBuilder rb{ctx, 2};
413 rb.Push(RESULT_SUCCESS); 421 rb.Push(RESULT_SUCCESS);
422 rb.Push(0);
414} 423}
415 424
416void Hid::SendKeyboardLockKeyEvent(Kernel::HLERequestContext& ctx) { 425void Hid::ActivateSixAxisSensor(Kernel::HLERequestContext& ctx) {
417 IPC::RequestParser rp{ctx}; 426 IPC::RequestParser rp{ctx};
418 const auto flags{rp.Pop<u32>()}; 427 struct Parameters {
419 LOG_WARNING(Service_HID, "(STUBBED) called. flags={}", flags); 428 Controller_NPad::DeviceHandle sixaxis_handle{};
429 INSERT_PADDING_WORDS(1);
430 u64 applet_resource_user_id{};
431 };
420 432
421 IPC::ResponseBuilder rb{ctx, 2}; 433 const auto parameters{rp.PopRaw<Parameters>()};
422 rb.Push(RESULT_SUCCESS);
423}
424 434
425void Hid::ActivateGesture(Kernel::HLERequestContext& ctx) { 435 applet_resource->GetController<Controller_NPad>(HidController::NPad).SetSixAxisEnabled(true);
426 IPC::RequestParser rp{ctx};
427 const auto unknown{rp.Pop<u32>()};
428 const auto applet_resource_user_id{rp.Pop<u64>()};
429 436
430 LOG_DEBUG(Service_HID, "called, unknown={}, applet_resource_user_id={}", unknown, 437 LOG_DEBUG(Service_HID,
431 applet_resource_user_id); 438 "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
439 parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
440 parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
432 441
433 applet_resource->ActivateController(HidController::Gesture);
434 IPC::ResponseBuilder rb{ctx, 2}; 442 IPC::ResponseBuilder rb{ctx, 2};
435 rb.Push(RESULT_SUCCESS); 443 rb.Push(RESULT_SUCCESS);
436} 444}
437 445
438void Hid::ActivateNpadWithRevision(Kernel::HLERequestContext& ctx) { 446void Hid::DeactivateSixAxisSensor(Kernel::HLERequestContext& ctx) {
439 // Should have no effect with how our npad sets up the data
440 IPC::RequestParser rp{ctx}; 447 IPC::RequestParser rp{ctx};
441 const auto unknown{rp.Pop<u32>()}; 448 struct Parameters {
442 const auto applet_resource_user_id{rp.Pop<u64>()}; 449 Controller_NPad::DeviceHandle sixaxis_handle{};
450 INSERT_PADDING_WORDS(1);
451 u64 applet_resource_user_id{};
452 };
443 453
444 LOG_DEBUG(Service_HID, "called, unknown={}, applet_resource_user_id={}", unknown, 454 const auto parameters{rp.PopRaw<Parameters>()};
445 applet_resource_user_id); 455
456 applet_resource->GetController<Controller_NPad>(HidController::NPad).SetSixAxisEnabled(false);
457
458 LOG_DEBUG(Service_HID,
459 "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
460 parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
461 parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
446 462
447 applet_resource->ActivateController(HidController::NPad);
448 IPC::ResponseBuilder rb{ctx, 2}; 463 IPC::ResponseBuilder rb{ctx, 2};
449 rb.Push(RESULT_SUCCESS); 464 rb.Push(RESULT_SUCCESS);
450} 465}
451 466
452void Hid::StartSixAxisSensor(Kernel::HLERequestContext& ctx) { 467void Hid::StartSixAxisSensor(Kernel::HLERequestContext& ctx) {
453 IPC::RequestParser rp{ctx}; 468 IPC::RequestParser rp{ctx};
454 const auto handle{rp.Pop<u32>()}; 469 struct Parameters {
455 const auto applet_resource_user_id{rp.Pop<u64>()}; 470 Controller_NPad::DeviceHandle sixaxis_handle{};
471 INSERT_PADDING_WORDS(1);
472 u64 applet_resource_user_id{};
473 };
456 474
457 LOG_WARNING(Service_HID, "(STUBBED) called, handle={}, applet_resource_user_id={}", handle, 475 const auto parameters{rp.PopRaw<Parameters>()};
458 applet_resource_user_id); 476
477 applet_resource->GetController<Controller_NPad>(HidController::NPad).SetSixAxisEnabled(true);
478
479 LOG_DEBUG(Service_HID,
480 "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
481 parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
482 parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
459 483
460 IPC::ResponseBuilder rb{ctx, 2}; 484 IPC::ResponseBuilder rb{ctx, 2};
461 rb.Push(RESULT_SUCCESS); 485 rb.Push(RESULT_SUCCESS);
@@ -463,11 +487,20 @@ void Hid::StartSixAxisSensor(Kernel::HLERequestContext& ctx) {
463 487
464void Hid::StopSixAxisSensor(Kernel::HLERequestContext& ctx) { 488void Hid::StopSixAxisSensor(Kernel::HLERequestContext& ctx) {
465 IPC::RequestParser rp{ctx}; 489 IPC::RequestParser rp{ctx};
466 const auto handle{rp.Pop<u32>()}; 490 struct Parameters {
467 const auto applet_resource_user_id{rp.Pop<u64>()}; 491 Controller_NPad::DeviceHandle sixaxis_handle{};
492 INSERT_PADDING_WORDS(1);
493 u64 applet_resource_user_id{};
494 };
468 495
469 LOG_WARNING(Service_HID, "(STUBBED) called, handle={}, applet_resource_user_id={}", handle, 496 const auto parameters{rp.PopRaw<Parameters>()};
470 applet_resource_user_id); 497
498 applet_resource->GetController<Controller_NPad>(HidController::NPad).SetSixAxisEnabled(false);
499
500 LOG_DEBUG(Service_HID,
501 "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
502 parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
503 parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
471 504
472 IPC::ResponseBuilder rb{ctx, 2}; 505 IPC::ResponseBuilder rb{ctx, 2};
473 rb.Push(RESULT_SUCCESS); 506 rb.Push(RESULT_SUCCESS);
@@ -475,12 +508,21 @@ void Hid::StopSixAxisSensor(Kernel::HLERequestContext& ctx) {
475 508
476void Hid::EnableSixAxisSensorFusion(Kernel::HLERequestContext& ctx) { 509void Hid::EnableSixAxisSensorFusion(Kernel::HLERequestContext& ctx) {
477 IPC::RequestParser rp{ctx}; 510 IPC::RequestParser rp{ctx};
478 [[maybe_unused]] const auto enable{rp.Pop<bool>()}; 511 struct Parameters {
479 const auto handle{rp.Pop<u32>()}; 512 bool enable_sixaxis_sensor_fusion{};
480 const auto applet_resource_user_id{rp.Pop<u64>()}; 513 INSERT_PADDING_BYTES(3);
514 Controller_NPad::DeviceHandle sixaxis_handle{};
515 u64 applet_resource_user_id{};
516 };
481 517
482 LOG_WARNING(Service_HID, "(STUBBED) called, handle={}, applet_resource_user_id={}", handle, 518 const auto parameters{rp.PopRaw<Parameters>()};
483 applet_resource_user_id); 519
520 LOG_WARNING(Service_HID,
521 "(STUBBED) called, enable_sixaxis_sensor_fusion={}, npad_type={}, npad_id={}, "
522 "device_index={}, applet_resource_user_id={}",
523 parameters.enable_sixaxis_sensor_fusion, parameters.sixaxis_handle.npad_type,
524 parameters.sixaxis_handle.npad_id, parameters.sixaxis_handle.device_index,
525 parameters.applet_resource_user_id);
484 526
485 IPC::ResponseBuilder rb{ctx, 2}; 527 IPC::ResponseBuilder rb{ctx, 2};
486 rb.Push(RESULT_SUCCESS); 528 rb.Push(RESULT_SUCCESS);
@@ -488,14 +530,17 @@ void Hid::EnableSixAxisSensorFusion(Kernel::HLERequestContext& ctx) {
488 530
489void Hid::SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { 531void Hid::SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) {
490 IPC::RequestParser rp{ctx}; 532 IPC::RequestParser rp{ctx};
491 const auto handle{rp.Pop<u32>()}; 533 const auto sixaxis_handle{rp.PopRaw<Controller_NPad::DeviceHandle>()};
492 const auto drift_mode{rp.Pop<u32>()}; 534 const auto drift_mode{rp.PopEnum<Controller_NPad::GyroscopeZeroDriftMode>()};
493 const auto applet_resource_user_id{rp.Pop<u64>()}; 535 const auto applet_resource_user_id{rp.Pop<u64>()};
494 536
495 applet_resource->GetController<Controller_NPad>(HidController::NPad) 537 applet_resource->GetController<Controller_NPad>(HidController::NPad)
496 .SetGyroscopeZeroDriftMode(Controller_NPad::GyroscopeZeroDriftMode{drift_mode}); 538 .SetGyroscopeZeroDriftMode(drift_mode);
497 539
498 LOG_DEBUG(Service_HID, "called, handle={}, drift_mode={}, applet_resource_user_id={}", handle, 540 LOG_DEBUG(Service_HID,
541 "called, npad_type={}, npad_id={}, device_index={}, drift_mode={}, "
542 "applet_resource_user_id={}",
543 sixaxis_handle.npad_type, sixaxis_handle.npad_id, sixaxis_handle.device_index,
499 drift_mode, applet_resource_user_id); 544 drift_mode, applet_resource_user_id);
500 545
501 IPC::ResponseBuilder rb{ctx, 2}; 546 IPC::ResponseBuilder rb{ctx, 2};
@@ -504,29 +549,42 @@ void Hid::SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) {
504 549
505void Hid::GetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { 550void Hid::GetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) {
506 IPC::RequestParser rp{ctx}; 551 IPC::RequestParser rp{ctx};
507 const auto handle{rp.Pop<u32>()}; 552 struct Parameters {
508 const auto applet_resource_user_id{rp.Pop<u64>()}; 553 Controller_NPad::DeviceHandle sixaxis_handle{};
554 INSERT_PADDING_WORDS(1);
555 u64 applet_resource_user_id{};
556 };
557
558 const auto parameters{rp.PopRaw<Parameters>()};
509 559
510 LOG_DEBUG(Service_HID, "called, handle={}, applet_resource_user_id={}", handle, 560 LOG_DEBUG(Service_HID,
511 applet_resource_user_id); 561 "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
562 parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
563 parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
512 564
513 IPC::ResponseBuilder rb{ctx, 3}; 565 IPC::ResponseBuilder rb{ctx, 3};
514 rb.Push(RESULT_SUCCESS); 566 rb.Push(RESULT_SUCCESS);
515 rb.Push<u32>( 567 rb.PushEnum(applet_resource->GetController<Controller_NPad>(HidController::NPad)
516 static_cast<u32>(applet_resource->GetController<Controller_NPad>(HidController::NPad) 568 .GetGyroscopeZeroDriftMode());
517 .GetGyroscopeZeroDriftMode()));
518} 569}
519 570
520void Hid::ResetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { 571void Hid::ResetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) {
521 IPC::RequestParser rp{ctx}; 572 IPC::RequestParser rp{ctx};
522 const auto handle{rp.Pop<u32>()}; 573 struct Parameters {
523 const auto applet_resource_user_id{rp.Pop<u64>()}; 574 Controller_NPad::DeviceHandle sixaxis_handle{};
575 INSERT_PADDING_WORDS(1);
576 u64 applet_resource_user_id{};
577 };
578
579 const auto parameters{rp.PopRaw<Parameters>()};
524 580
525 applet_resource->GetController<Controller_NPad>(HidController::NPad) 581 applet_resource->GetController<Controller_NPad>(HidController::NPad)
526 .SetGyroscopeZeroDriftMode(Controller_NPad::GyroscopeZeroDriftMode::Standard); 582 .SetGyroscopeZeroDriftMode(Controller_NPad::GyroscopeZeroDriftMode::Standard);
527 583
528 LOG_DEBUG(Service_HID, "called, handle={}, applet_resource_user_id={}", handle, 584 LOG_DEBUG(Service_HID,
529 applet_resource_user_id); 585 "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
586 parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
587 parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
530 588
531 IPC::ResponseBuilder rb{ctx, 2}; 589 IPC::ResponseBuilder rb{ctx, 2};
532 rb.Push(RESULT_SUCCESS); 590 rb.Push(RESULT_SUCCESS);
@@ -534,11 +592,18 @@ void Hid::ResetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) {
534 592
535void Hid::IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx) { 593void Hid::IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx) {
536 IPC::RequestParser rp{ctx}; 594 IPC::RequestParser rp{ctx};
537 const auto handle{rp.Pop<u32>()}; 595 struct Parameters {
538 const auto applet_resource_user_id{rp.Pop<u64>()}; 596 Controller_NPad::DeviceHandle sixaxis_handle{};
597 INSERT_PADDING_WORDS(1);
598 u64 applet_resource_user_id{};
599 };
600
601 const auto parameters{rp.PopRaw<Parameters>()};
539 602
540 LOG_DEBUG(Service_HID, "called, handle={}, applet_resource_user_id={}", handle, 603 LOG_DEBUG(Service_HID,
541 applet_resource_user_id); 604 "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
605 parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
606 parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
542 607
543 IPC::ResponseBuilder rb{ctx, 3}; 608 IPC::ResponseBuilder rb{ctx, 3};
544 rb.Push(RESULT_SUCCESS); 609 rb.Push(RESULT_SUCCESS);
@@ -546,15 +611,34 @@ void Hid::IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx) {
546 .IsSixAxisSensorAtRest()); 611 .IsSixAxisSensorAtRest());
547} 612}
548 613
614void Hid::ActivateGesture(Kernel::HLERequestContext& ctx) {
615 IPC::RequestParser rp{ctx};
616 struct Parameters {
617 u32 unknown{};
618 INSERT_PADDING_WORDS(1);
619 u64 applet_resource_user_id{};
620 };
621
622 const auto parameters{rp.PopRaw<Parameters>()};
623
624 applet_resource->ActivateController(HidController::Gesture);
625
626 LOG_DEBUG(Service_HID, "called, unknown={}, applet_resource_user_id={}", parameters.unknown,
627 parameters.applet_resource_user_id);
628
629 IPC::ResponseBuilder rb{ctx, 2};
630 rb.Push(RESULT_SUCCESS);
631}
632
549void Hid::SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) { 633void Hid::SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) {
550 IPC::RequestParser rp{ctx}; 634 IPC::RequestParser rp{ctx};
551 const auto supported_styleset{rp.Pop<u32>()}; 635 const auto supported_styleset{rp.Pop<u32>()};
552 636
553 LOG_DEBUG(Service_HID, "called, supported_styleset={}", supported_styleset);
554
555 applet_resource->GetController<Controller_NPad>(HidController::NPad) 637 applet_resource->GetController<Controller_NPad>(HidController::NPad)
556 .SetSupportedStyleSet({supported_styleset}); 638 .SetSupportedStyleSet({supported_styleset});
557 639
640 LOG_DEBUG(Service_HID, "called, supported_styleset={}", supported_styleset);
641
558 IPC::ResponseBuilder rb{ctx, 2}; 642 IPC::ResponseBuilder rb{ctx, 2};
559 rb.Push(RESULT_SUCCESS); 643 rb.Push(RESULT_SUCCESS);
560} 644}
@@ -565,21 +649,22 @@ void Hid::GetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) {
565 649
566 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); 650 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
567 651
568 auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
569
570 IPC::ResponseBuilder rb{ctx, 3}; 652 IPC::ResponseBuilder rb{ctx, 3};
571 rb.Push(RESULT_SUCCESS); 653 rb.Push(RESULT_SUCCESS);
572 rb.Push<u32>(controller.GetSupportedStyleSet().raw); 654 rb.Push(applet_resource->GetController<Controller_NPad>(HidController::NPad)
655 .GetSupportedStyleSet()
656 .raw);
573} 657}
574 658
575void Hid::SetSupportedNpadIdType(Kernel::HLERequestContext& ctx) { 659void Hid::SetSupportedNpadIdType(Kernel::HLERequestContext& ctx) {
576 IPC::RequestParser rp{ctx}; 660 IPC::RequestParser rp{ctx};
577 const auto applet_resource_user_id{rp.Pop<u64>()}; 661 const auto applet_resource_user_id{rp.Pop<u64>()};
578 662
663 applet_resource->GetController<Controller_NPad>(HidController::NPad)
664 .SetSupportedNpadIdTypes(ctx.ReadBuffer().data(), ctx.GetReadBufferSize());
665
579 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); 666 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
580 667
581 applet_resource->GetController<Controller_NPad>(HidController::NPad)
582 .SetSupportedNPadIdTypes(ctx.ReadBuffer().data(), ctx.GetReadBufferSize());
583 IPC::ResponseBuilder rb{ctx, 2}; 668 IPC::ResponseBuilder rb{ctx, 2};
584 rb.Push(RESULT_SUCCESS); 669 rb.Push(RESULT_SUCCESS);
585} 670}
@@ -588,48 +673,62 @@ void Hid::ActivateNpad(Kernel::HLERequestContext& ctx) {
588 IPC::RequestParser rp{ctx}; 673 IPC::RequestParser rp{ctx};
589 const auto applet_resource_user_id{rp.Pop<u64>()}; 674 const auto applet_resource_user_id{rp.Pop<u64>()};
590 675
676 applet_resource->ActivateController(HidController::NPad);
677
591 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); 678 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
592 679
593 IPC::ResponseBuilder rb{ctx, 2}; 680 IPC::ResponseBuilder rb{ctx, 2};
594 rb.Push(RESULT_SUCCESS); 681 rb.Push(RESULT_SUCCESS);
595 applet_resource->ActivateController(HidController::NPad);
596} 682}
597 683
598void Hid::DeactivateNpad(Kernel::HLERequestContext& ctx) { 684void Hid::DeactivateNpad(Kernel::HLERequestContext& ctx) {
599 IPC::RequestParser rp{ctx}; 685 IPC::RequestParser rp{ctx};
600 const auto applet_resource_user_id{rp.Pop<u64>()}; 686 const auto applet_resource_user_id{rp.Pop<u64>()};
601 687
688 applet_resource->DeactivateController(HidController::NPad);
689
602 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); 690 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
603 691
604 IPC::ResponseBuilder rb{ctx, 2}; 692 IPC::ResponseBuilder rb{ctx, 2};
605 rb.Push(RESULT_SUCCESS); 693 rb.Push(RESULT_SUCCESS);
606 applet_resource->DeactivateController(HidController::NPad);
607} 694}
608 695
609void Hid::AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx) { 696void Hid::AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx) {
610 IPC::RequestParser rp{ctx}; 697 IPC::RequestParser rp{ctx};
611 const auto npad_id{rp.Pop<u32>()}; 698 struct Parameters {
612 const auto applet_resource_user_id{rp.Pop<u64>()}; 699 u32 npad_id{};
613 const auto unknown{rp.Pop<u64>()}; 700 INSERT_PADDING_WORDS(1);
701 u64 applet_resource_user_id{};
702 u64 unknown{};
703 };
614 704
615 LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}, unknown={}", npad_id, 705 const auto parameters{rp.PopRaw<Parameters>()};
616 applet_resource_user_id, unknown); 706
707 LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}, unknown={}",
708 parameters.npad_id, parameters.applet_resource_user_id, parameters.unknown);
617 709
618 IPC::ResponseBuilder rb{ctx, 2, 1}; 710 IPC::ResponseBuilder rb{ctx, 2, 1};
619 rb.Push(RESULT_SUCCESS); 711 rb.Push(RESULT_SUCCESS);
620 rb.PushCopyObjects(applet_resource->GetController<Controller_NPad>(HidController::NPad) 712 rb.PushCopyObjects(applet_resource->GetController<Controller_NPad>(HidController::NPad)
621 .GetStyleSetChangedEvent(npad_id)); 713 .GetStyleSetChangedEvent(parameters.npad_id));
622} 714}
623 715
624void Hid::DisconnectNpad(Kernel::HLERequestContext& ctx) { 716void Hid::DisconnectNpad(Kernel::HLERequestContext& ctx) {
625 IPC::RequestParser rp{ctx}; 717 IPC::RequestParser rp{ctx};
626 const auto npad_id{rp.Pop<u32>()}; 718 struct Parameters {
627 const auto applet_resource_user_id{rp.Pop<u64>()}; 719 u32 npad_id{};
720 INSERT_PADDING_WORDS(1);
721 u64 applet_resource_user_id{};
722 };
628 723
629 LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}", npad_id, 724 const auto parameters{rp.PopRaw<Parameters>()};
630 applet_resource_user_id); 725
726 applet_resource->GetController<Controller_NPad>(HidController::NPad)
727 .DisconnectNpad(parameters.npad_id);
728
729 LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id,
730 parameters.applet_resource_user_id);
631 731
632 applet_resource->GetController<Controller_NPad>(HidController::NPad).DisconnectNPad(npad_id);
633 IPC::ResponseBuilder rb{ctx, 2}; 732 IPC::ResponseBuilder rb{ctx, 2};
634 rb.Push(RESULT_SUCCESS); 733 rb.Push(RESULT_SUCCESS);
635} 734}
@@ -642,22 +741,41 @@ void Hid::GetPlayerLedPattern(Kernel::HLERequestContext& ctx) {
642 741
643 IPC::ResponseBuilder rb{ctx, 4}; 742 IPC::ResponseBuilder rb{ctx, 4};
644 rb.Push(RESULT_SUCCESS); 743 rb.Push(RESULT_SUCCESS);
645 rb.PushRaw<u64>(applet_resource->GetController<Controller_NPad>(HidController::NPad) 744 rb.Push(applet_resource->GetController<Controller_NPad>(HidController::NPad)
646 .GetLedPattern(npad_id) 745 .GetLedPattern(npad_id)
647 .raw); 746 .raw);
747}
748
749void Hid::ActivateNpadWithRevision(Kernel::HLERequestContext& ctx) {
750 // Should have no effect with how our npad sets up the data
751 IPC::RequestParser rp{ctx};
752 struct Parameters {
753 u32 unknown{};
754 INSERT_PADDING_WORDS(1);
755 u64 applet_resource_user_id{};
756 };
757
758 const auto parameters{rp.PopRaw<Parameters>()};
759
760 applet_resource->ActivateController(HidController::NPad);
761
762 LOG_DEBUG(Service_HID, "called, unknown={}, applet_resource_user_id={}", parameters.unknown,
763 parameters.applet_resource_user_id);
764
765 IPC::ResponseBuilder rb{ctx, 2};
766 rb.Push(RESULT_SUCCESS);
648} 767}
649 768
650void Hid::SetNpadJoyHoldType(Kernel::HLERequestContext& ctx) { 769void Hid::SetNpadJoyHoldType(Kernel::HLERequestContext& ctx) {
651 IPC::RequestParser rp{ctx}; 770 IPC::RequestParser rp{ctx};
652 const auto applet_resource_user_id{rp.Pop<u64>()}; 771 const auto applet_resource_user_id{rp.Pop<u64>()};
653 const auto hold_type{rp.Pop<u64>()}; 772 const auto hold_type{rp.PopEnum<Controller_NPad::NpadHoldType>()};
773
774 applet_resource->GetController<Controller_NPad>(HidController::NPad).SetHoldType(hold_type);
654 775
655 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, hold_type={}", 776 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, hold_type={}",
656 applet_resource_user_id, hold_type); 777 applet_resource_user_id, hold_type);
657 778
658 auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
659 controller.SetHoldType(Controller_NPad::NpadHoldType{hold_type});
660
661 IPC::ResponseBuilder rb{ctx, 2}; 779 IPC::ResponseBuilder rb{ctx, 2};
662 rb.Push(RESULT_SUCCESS); 780 rb.Push(RESULT_SUCCESS);
663} 781}
@@ -668,22 +786,26 @@ void Hid::GetNpadJoyHoldType(Kernel::HLERequestContext& ctx) {
668 786
669 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); 787 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
670 788
671 const auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
672 IPC::ResponseBuilder rb{ctx, 4}; 789 IPC::ResponseBuilder rb{ctx, 4};
673 rb.Push(RESULT_SUCCESS); 790 rb.Push(RESULT_SUCCESS);
674 rb.Push<u64>(static_cast<u64>(controller.GetHoldType())); 791 rb.PushEnum(applet_resource->GetController<Controller_NPad>(HidController::NPad).GetHoldType());
675} 792}
676 793
677void Hid::SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx) { 794void Hid::SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx) {
678 IPC::RequestParser rp{ctx}; 795 IPC::RequestParser rp{ctx};
679 const auto npad_id{rp.Pop<u32>()}; 796 struct Parameters {
680 const auto applet_resource_user_id{rp.Pop<u64>()}; 797 u32 npad_id{};
798 INSERT_PADDING_WORDS(1);
799 u64 applet_resource_user_id{};
800 };
681 801
682 LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}", npad_id, 802 const auto parameters{rp.PopRaw<Parameters>()};
683 applet_resource_user_id); 803
804 applet_resource->GetController<Controller_NPad>(HidController::NPad)
805 .SetNpadMode(parameters.npad_id, Controller_NPad::NpadAssignments::Single);
684 806
685 auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); 807 LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}",
686 controller.SetNpadMode(npad_id, Controller_NPad::NPadAssignments::Single); 808 parameters.npad_id, parameters.applet_resource_user_id);
687 809
688 IPC::ResponseBuilder rb{ctx, 2}; 810 IPC::ResponseBuilder rb{ctx, 2};
689 rb.Push(RESULT_SUCCESS); 811 rb.Push(RESULT_SUCCESS);
@@ -692,16 +814,22 @@ void Hid::SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx
692void Hid::SetNpadJoyAssignmentModeSingle(Kernel::HLERequestContext& ctx) { 814void Hid::SetNpadJoyAssignmentModeSingle(Kernel::HLERequestContext& ctx) {
693 // TODO: Check the differences between this and SetNpadJoyAssignmentModeSingleByDefault 815 // TODO: Check the differences between this and SetNpadJoyAssignmentModeSingleByDefault
694 IPC::RequestParser rp{ctx}; 816 IPC::RequestParser rp{ctx};
695 const auto npad_id{rp.Pop<u32>()}; 817 struct Parameters {
696 const auto applet_resource_user_id{rp.Pop<u64>()}; 818 u32 npad_id{};
697 const auto npad_joy_device_type{rp.Pop<u64>()}; 819 INSERT_PADDING_WORDS(1);
820 u64 applet_resource_user_id{};
821 u64 npad_joy_device_type{};
822 };
823
824 const auto parameters{rp.PopRaw<Parameters>()};
825
826 applet_resource->GetController<Controller_NPad>(HidController::NPad)
827 .SetNpadMode(parameters.npad_id, Controller_NPad::NpadAssignments::Single);
698 828
699 LOG_WARNING(Service_HID, 829 LOG_WARNING(Service_HID,
700 "(STUBBED) called, npad_id={}, applet_resource_user_id={}, npad_joy_device_type={}", 830 "(STUBBED) called, npad_id={}, applet_resource_user_id={}, npad_joy_device_type={}",
701 npad_id, applet_resource_user_id, npad_joy_device_type); 831 parameters.npad_id, parameters.applet_resource_user_id,
702 832 parameters.npad_joy_device_type);
703 auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
704 controller.SetNpadMode(npad_id, Controller_NPad::NPadAssignments::Single);
705 833
706 IPC::ResponseBuilder rb{ctx, 2}; 834 IPC::ResponseBuilder rb{ctx, 2};
707 rb.Push(RESULT_SUCCESS); 835 rb.Push(RESULT_SUCCESS);
@@ -709,14 +837,19 @@ void Hid::SetNpadJoyAssignmentModeSingle(Kernel::HLERequestContext& ctx) {
709 837
710void Hid::SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) { 838void Hid::SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) {
711 IPC::RequestParser rp{ctx}; 839 IPC::RequestParser rp{ctx};
712 const auto npad_id{rp.Pop<u32>()}; 840 struct Parameters {
713 const auto applet_resource_user_id{rp.Pop<u64>()}; 841 u32 npad_id{};
842 INSERT_PADDING_WORDS(1);
843 u64 applet_resource_user_id{};
844 };
845
846 const auto parameters{rp.PopRaw<Parameters>()};
714 847
715 LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}", npad_id, 848 applet_resource->GetController<Controller_NPad>(HidController::NPad)
716 applet_resource_user_id); 849 .SetNpadMode(parameters.npad_id, Controller_NPad::NpadAssignments::Dual);
717 850
718 auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); 851 LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}",
719 controller.SetNpadMode(npad_id, Controller_NPad::NPadAssignments::Dual); 852 parameters.npad_id, parameters.applet_resource_user_id);
720 853
721 IPC::ResponseBuilder rb{ctx, 2}; 854 IPC::ResponseBuilder rb{ctx, 2};
722 rb.Push(RESULT_SUCCESS); 855 rb.Push(RESULT_SUCCESS);
@@ -728,12 +861,12 @@ void Hid::MergeSingleJoyAsDualJoy(Kernel::HLERequestContext& ctx) {
728 const auto npad_id_2{rp.Pop<u32>()}; 861 const auto npad_id_2{rp.Pop<u32>()};
729 const auto applet_resource_user_id{rp.Pop<u64>()}; 862 const auto applet_resource_user_id{rp.Pop<u64>()};
730 863
864 applet_resource->GetController<Controller_NPad>(HidController::NPad)
865 .MergeSingleJoyAsDualJoy(npad_id_1, npad_id_2);
866
731 LOG_DEBUG(Service_HID, "called, npad_id_1={}, npad_id_2={}, applet_resource_user_id={}", 867 LOG_DEBUG(Service_HID, "called, npad_id_1={}, npad_id_2={}, applet_resource_user_id={}",
732 npad_id_1, npad_id_2, applet_resource_user_id); 868 npad_id_1, npad_id_2, applet_resource_user_id);
733 869
734 auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
735 controller.MergeSingleJoyAsDualJoy(npad_id_1, npad_id_2);
736
737 IPC::ResponseBuilder rb{ctx, 2}; 870 IPC::ResponseBuilder rb{ctx, 2};
738 rb.Push(RESULT_SUCCESS); 871 rb.Push(RESULT_SUCCESS);
739} 872}
@@ -742,9 +875,9 @@ void Hid::StartLrAssignmentMode(Kernel::HLERequestContext& ctx) {
742 IPC::RequestParser rp{ctx}; 875 IPC::RequestParser rp{ctx};
743 const auto applet_resource_user_id{rp.Pop<u64>()}; 876 const auto applet_resource_user_id{rp.Pop<u64>()};
744 877
878 applet_resource->GetController<Controller_NPad>(HidController::NPad).StartLRAssignmentMode();
879
745 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); 880 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
746 auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
747 controller.StartLRAssignmentMode();
748 881
749 IPC::ResponseBuilder rb{ctx, 2}; 882 IPC::ResponseBuilder rb{ctx, 2};
750 rb.Push(RESULT_SUCCESS); 883 rb.Push(RESULT_SUCCESS);
@@ -754,9 +887,9 @@ void Hid::StopLrAssignmentMode(Kernel::HLERequestContext& ctx) {
754 IPC::RequestParser rp{ctx}; 887 IPC::RequestParser rp{ctx};
755 const auto applet_resource_user_id{rp.Pop<u64>()}; 888 const auto applet_resource_user_id{rp.Pop<u64>()};
756 889
890 applet_resource->GetController<Controller_NPad>(HidController::NPad).StopLRAssignmentMode();
891
757 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); 892 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
758 auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
759 controller.StopLRAssignmentMode();
760 893
761 IPC::ResponseBuilder rb{ctx, 2}; 894 IPC::ResponseBuilder rb{ctx, 2};
762 rb.Push(RESULT_SUCCESS); 895 rb.Push(RESULT_SUCCESS);
@@ -765,13 +898,13 @@ void Hid::StopLrAssignmentMode(Kernel::HLERequestContext& ctx) {
765void Hid::SetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx) { 898void Hid::SetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx) {
766 IPC::RequestParser rp{ctx}; 899 IPC::RequestParser rp{ctx};
767 const auto applet_resource_user_id{rp.Pop<u64>()}; 900 const auto applet_resource_user_id{rp.Pop<u64>()};
768 const auto mode{rp.Pop<u64>()}; 901 const auto activation_mode{rp.PopEnum<Controller_NPad::NpadHandheldActivationMode>()};
769
770 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, mode={}", applet_resource_user_id,
771 mode);
772 902
773 applet_resource->GetController<Controller_NPad>(HidController::NPad) 903 applet_resource->GetController<Controller_NPad>(HidController::NPad)
774 .SetNpadHandheldActivationMode(Controller_NPad::NpadHandheldActivationMode{mode}); 904 .SetNpadHandheldActivationMode(activation_mode);
905
906 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, activation_mode={}",
907 applet_resource_user_id, activation_mode);
775 908
776 IPC::ResponseBuilder rb{ctx, 2}; 909 IPC::ResponseBuilder rb{ctx, 2};
777 rb.Push(RESULT_SUCCESS); 910 rb.Push(RESULT_SUCCESS);
@@ -785,23 +918,24 @@ void Hid::GetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx) {
785 918
786 IPC::ResponseBuilder rb{ctx, 4}; 919 IPC::ResponseBuilder rb{ctx, 4};
787 rb.Push(RESULT_SUCCESS); 920 rb.Push(RESULT_SUCCESS);
788 rb.Push<u64>( 921 rb.PushEnum(applet_resource->GetController<Controller_NPad>(HidController::NPad)
789 static_cast<u64>(applet_resource->GetController<Controller_NPad>(HidController::NPad) 922 .GetNpadHandheldActivationMode());
790 .GetNpadHandheldActivationMode()));
791} 923}
792 924
793void Hid::SwapNpadAssignment(Kernel::HLERequestContext& ctx) { 925void Hid::SwapNpadAssignment(Kernel::HLERequestContext& ctx) {
794 IPC::RequestParser rp{ctx}; 926 IPC::RequestParser rp{ctx};
795 const auto npad_1{rp.Pop<u32>()}; 927 const auto npad_id_1{rp.Pop<u32>()};
796 const auto npad_2{rp.Pop<u32>()}; 928 const auto npad_id_2{rp.Pop<u32>()};
797 const auto applet_resource_user_id{rp.Pop<u64>()}; 929 const auto applet_resource_user_id{rp.Pop<u64>()};
798 930
799 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, npad_1={}, npad_2={}", 931 const bool res = applet_resource->GetController<Controller_NPad>(HidController::NPad)
800 applet_resource_user_id, npad_1, npad_2); 932 .SwapNpadAssignment(npad_id_1, npad_id_2);
933
934 LOG_DEBUG(Service_HID, "called, npad_id_1={}, npad_id_2={}, applet_resource_user_id={}",
935 npad_id_1, npad_id_2, applet_resource_user_id);
801 936
802 auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
803 IPC::ResponseBuilder rb{ctx, 2}; 937 IPC::ResponseBuilder rb{ctx, 2};
804 if (controller.SwapNpadAssignment(npad_1, npad_2)) { 938 if (res) {
805 rb.Push(RESULT_SUCCESS); 939 rb.Push(RESULT_SUCCESS);
806 } else { 940 } else {
807 LOG_ERROR(Service_HID, "Npads are not connected!"); 941 LOG_ERROR(Service_HID, "Npads are not connected!");
@@ -811,144 +945,219 @@ void Hid::SwapNpadAssignment(Kernel::HLERequestContext& ctx) {
811 945
812void Hid::IsUnintendedHomeButtonInputProtectionEnabled(Kernel::HLERequestContext& ctx) { 946void Hid::IsUnintendedHomeButtonInputProtectionEnabled(Kernel::HLERequestContext& ctx) {
813 IPC::RequestParser rp{ctx}; 947 IPC::RequestParser rp{ctx};
814 const auto npad_id{rp.Pop<u32>()}; 948 struct Parameters {
815 const auto applet_resource_user_id{rp.Pop<u64>()}; 949 u32 npad_id{};
950 INSERT_PADDING_WORDS(1);
951 u64 applet_resource_user_id{};
952 };
816 953
817 LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}", npad_id, 954 const auto parameters{rp.PopRaw<Parameters>()};
818 applet_resource_user_id);
819 955
820 auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); 956 LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}",
957 parameters.npad_id, parameters.applet_resource_user_id);
821 958
822 IPC::ResponseBuilder rb{ctx, 3}; 959 IPC::ResponseBuilder rb{ctx, 3};
823 rb.Push(RESULT_SUCCESS); 960 rb.Push(RESULT_SUCCESS);
824 rb.Push<bool>(controller.IsUnintendedHomeButtonInputProtectionEnabled(npad_id)); 961 rb.Push(applet_resource->GetController<Controller_NPad>(HidController::NPad)
962 .IsUnintendedHomeButtonInputProtectionEnabled(parameters.npad_id));
825} 963}
826 964
827void Hid::EnableUnintendedHomeButtonInputProtection(Kernel::HLERequestContext& ctx) { 965void Hid::EnableUnintendedHomeButtonInputProtection(Kernel::HLERequestContext& ctx) {
828 IPC::RequestParser rp{ctx}; 966 IPC::RequestParser rp{ctx};
829 const auto unintended_home_button_input_protection{rp.Pop<bool>()}; 967 struct Parameters {
830 const auto npad_id{rp.Pop<u32>()}; 968 bool unintended_home_button_input_protection{};
831 const auto applet_resource_user_id{rp.Pop<u64>()}; 969 INSERT_PADDING_BYTES(3);
970 u32 npad_id{};
971 u64 applet_resource_user_id{};
972 };
973
974 const auto parameters{rp.PopRaw<Parameters>()};
975
976 applet_resource->GetController<Controller_NPad>(HidController::NPad)
977 .SetUnintendedHomeButtonInputProtectionEnabled(
978 parameters.unintended_home_button_input_protection, parameters.npad_id);
832 979
833 LOG_WARNING(Service_HID, 980 LOG_WARNING(Service_HID,
834 "(STUBBED) called, unintended_home_button_input_protection={}, npad_id={}," 981 "(STUBBED) called, unintended_home_button_input_protection={}, npad_id={},"
835 "applet_resource_user_id={}", 982 "applet_resource_user_id={}",
836 npad_id, unintended_home_button_input_protection, applet_resource_user_id); 983 parameters.unintended_home_button_input_protection, parameters.npad_id,
837 984 parameters.applet_resource_user_id);
838 auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
839 controller.SetUnintendedHomeButtonInputProtectionEnabled(
840 unintended_home_button_input_protection, npad_id);
841 985
842 IPC::ResponseBuilder rb{ctx, 2}; 986 IPC::ResponseBuilder rb{ctx, 2};
843 rb.Push(RESULT_SUCCESS); 987 rb.Push(RESULT_SUCCESS);
844} 988}
845 989
846void Hid::BeginPermitVibrationSession(Kernel::HLERequestContext& ctx) { 990void Hid::GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) {
847 IPC::RequestParser rp{ctx}; 991 IPC::RequestParser rp{ctx};
848 const auto applet_resource_user_id{rp.Pop<u64>()}; 992 const auto vibration_device_handle{rp.PopRaw<Controller_NPad::DeviceHandle>()};
993
994 VibrationDeviceInfo vibration_device_info;
995
996 vibration_device_info.type = VibrationDeviceType::LinearResonantActuator;
997
998 switch (vibration_device_handle.device_index) {
999 case Controller_NPad::DeviceIndex::Left:
1000 vibration_device_info.position = VibrationDevicePosition::Left;
1001 break;
1002 case Controller_NPad::DeviceIndex::Right:
1003 vibration_device_info.position = VibrationDevicePosition::Right;
1004 break;
1005 case Controller_NPad::DeviceIndex::None:
1006 default:
1007 UNREACHABLE_MSG("DeviceIndex should never be None!");
1008 vibration_device_info.position = VibrationDevicePosition::None;
1009 break;
1010 }
849 1011
850 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); 1012 LOG_DEBUG(Service_HID, "called, vibration_device_type={}, vibration_device_position={}",
1013 vibration_device_info.type, vibration_device_info.position);
1014
1015 IPC::ResponseBuilder rb{ctx, 4};
1016 rb.Push(RESULT_SUCCESS);
1017 rb.PushRaw(vibration_device_info);
1018}
1019
1020void Hid::SendVibrationValue(Kernel::HLERequestContext& ctx) {
1021 IPC::RequestParser rp{ctx};
1022 struct Parameters {
1023 Controller_NPad::DeviceHandle vibration_device_handle{};
1024 Controller_NPad::VibrationValue vibration_value{};
1025 INSERT_PADDING_WORDS(1);
1026 u64 applet_resource_user_id{};
1027 };
1028
1029 const auto parameters{rp.PopRaw<Parameters>()};
1030
1031 applet_resource->GetController<Controller_NPad>(HidController::NPad)
1032 .VibrateController(parameters.vibration_device_handle, parameters.vibration_value);
1033
1034 LOG_DEBUG(Service_HID,
1035 "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
1036 parameters.vibration_device_handle.npad_type,
1037 parameters.vibration_device_handle.npad_id,
1038 parameters.vibration_device_handle.device_index, parameters.applet_resource_user_id);
851 1039
852 applet_resource->GetController<Controller_NPad>(HidController::NPad).SetVibrationEnabled(true);
853 IPC::ResponseBuilder rb{ctx, 2}; 1040 IPC::ResponseBuilder rb{ctx, 2};
854 rb.Push(RESULT_SUCCESS); 1041 rb.Push(RESULT_SUCCESS);
855} 1042}
856 1043
857void Hid::EndPermitVibrationSession(Kernel::HLERequestContext& ctx) { 1044void Hid::GetActualVibrationValue(Kernel::HLERequestContext& ctx) {
1045 IPC::RequestParser rp{ctx};
1046 struct Parameters {
1047 Controller_NPad::DeviceHandle vibration_device_handle{};
1048 INSERT_PADDING_WORDS(1);
1049 u64 applet_resource_user_id{};
1050 };
1051
1052 const auto parameters{rp.PopRaw<Parameters>()};
1053
1054 LOG_DEBUG(Service_HID,
1055 "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
1056 parameters.vibration_device_handle.npad_type,
1057 parameters.vibration_device_handle.npad_id,
1058 parameters.vibration_device_handle.device_index, parameters.applet_resource_user_id);
1059
1060 IPC::ResponseBuilder rb{ctx, 6};
1061 rb.Push(RESULT_SUCCESS);
1062 rb.PushRaw(applet_resource->GetController<Controller_NPad>(HidController::NPad)
1063 .GetLastVibration(parameters.vibration_device_handle));
1064}
1065
1066void Hid::CreateActiveVibrationDeviceList(Kernel::HLERequestContext& ctx) {
858 LOG_DEBUG(Service_HID, "called"); 1067 LOG_DEBUG(Service_HID, "called");
859 1068
860 applet_resource->GetController<Controller_NPad>(HidController::NPad).SetVibrationEnabled(false); 1069 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
861 IPC::ResponseBuilder rb{ctx, 2};
862 rb.Push(RESULT_SUCCESS); 1070 rb.Push(RESULT_SUCCESS);
1071 rb.PushIpcInterface<IActiveVibrationDeviceList>(applet_resource);
863} 1072}
864 1073
865void Hid::SendVibrationValue(Kernel::HLERequestContext& ctx) { 1074void Hid::PermitVibration(Kernel::HLERequestContext& ctx) {
866 IPC::RequestParser rp{ctx}; 1075 IPC::RequestParser rp{ctx};
867 const auto controller{rp.Pop<u32>()}; 1076 const auto can_vibrate{rp.Pop<bool>()};
868 const auto vibration_values{rp.PopRaw<Controller_NPad::Vibration>()};
869 const auto applet_resource_user_id{rp.Pop<u64>()};
870 1077
871 LOG_DEBUG(Service_HID, "called, controller={}, applet_resource_user_id={}", controller, 1078 Settings::values.vibration_enabled.SetValue(can_vibrate);
872 applet_resource_user_id); 1079
1080 LOG_DEBUG(Service_HID, "called, can_vibrate={}", can_vibrate);
873 1081
874 IPC::ResponseBuilder rb{ctx, 2}; 1082 IPC::ResponseBuilder rb{ctx, 2};
875 rb.Push(RESULT_SUCCESS); 1083 rb.Push(RESULT_SUCCESS);
1084}
876 1085
877 applet_resource->GetController<Controller_NPad>(HidController::NPad) 1086void Hid::IsVibrationPermitted(Kernel::HLERequestContext& ctx) {
878 .VibrateController({controller}, {vibration_values}); 1087 LOG_DEBUG(Service_HID, "called");
1088
1089 IPC::ResponseBuilder rb{ctx, 3};
1090 rb.Push(RESULT_SUCCESS);
1091 rb.Push(Settings::values.vibration_enabled.GetValue());
879} 1092}
880 1093
881void Hid::SendVibrationValues(Kernel::HLERequestContext& ctx) { 1094void Hid::SendVibrationValues(Kernel::HLERequestContext& ctx) {
882 IPC::RequestParser rp{ctx}; 1095 IPC::RequestParser rp{ctx};
883 const auto applet_resource_user_id{rp.Pop<u64>()}; 1096 const auto applet_resource_user_id{rp.Pop<u64>()};
884 1097
885 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id); 1098 const auto handles = ctx.ReadBuffer(0);
886
887 const auto controllers = ctx.ReadBuffer(0);
888 const auto vibrations = ctx.ReadBuffer(1); 1099 const auto vibrations = ctx.ReadBuffer(1);
889 1100
890 std::vector<u32> controller_list(controllers.size() / sizeof(u32)); 1101 std::vector<Controller_NPad::DeviceHandle> vibration_device_handles(
891 std::vector<Controller_NPad::Vibration> vibration_list(vibrations.size() / 1102 handles.size() / sizeof(Controller_NPad::DeviceHandle));
892 sizeof(Controller_NPad::Vibration)); 1103 std::vector<Controller_NPad::VibrationValue> vibration_values(
1104 vibrations.size() / sizeof(Controller_NPad::VibrationValue));
893 1105
894 std::memcpy(controller_list.data(), controllers.data(), controllers.size()); 1106 std::memcpy(vibration_device_handles.data(), handles.data(), handles.size());
895 std::memcpy(vibration_list.data(), vibrations.data(), vibrations.size()); 1107 std::memcpy(vibration_values.data(), vibrations.data(), vibrations.size());
896 1108
897 applet_resource->GetController<Controller_NPad>(HidController::NPad) 1109 applet_resource->GetController<Controller_NPad>(HidController::NPad)
898 .VibrateController(controller_list, vibration_list); 1110 .VibrateControllers(vibration_device_handles, vibration_values);
1111
1112 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
899 1113
900 IPC::ResponseBuilder rb{ctx, 2}; 1114 IPC::ResponseBuilder rb{ctx, 2};
901 rb.Push(RESULT_SUCCESS); 1115 rb.Push(RESULT_SUCCESS);
902} 1116}
903 1117
904void Hid::GetActualVibrationValue(Kernel::HLERequestContext& ctx) { 1118void Hid::BeginPermitVibrationSession(Kernel::HLERequestContext& ctx) {
905 IPC::RequestParser rp{ctx}; 1119 IPC::RequestParser rp{ctx};
906 const auto controller_id{rp.Pop<u32>()};
907 const auto applet_resource_user_id{rp.Pop<u64>()}; 1120 const auto applet_resource_user_id{rp.Pop<u64>()};
908 1121
909 LOG_DEBUG(Service_HID, "called, controller_id={}, applet_resource_user_id={}", controller_id, 1122 applet_resource->GetController<Controller_NPad>(HidController::NPad)
910 applet_resource_user_id); 1123 .SetPermitVibrationSession(true);
911
912 IPC::ResponseBuilder rb{ctx, 6};
913 rb.Push(RESULT_SUCCESS);
914 rb.PushRaw<Controller_NPad::Vibration>(
915 applet_resource->GetController<Controller_NPad>(HidController::NPad).GetLastVibration());
916}
917 1124
918void Hid::GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) { 1125 LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
919 LOG_DEBUG(Service_HID, "called");
920 1126
921 IPC::ResponseBuilder rb{ctx, 4}; 1127 IPC::ResponseBuilder rb{ctx, 2};
922 rb.Push(RESULT_SUCCESS); 1128 rb.Push(RESULT_SUCCESS);
923 rb.Push<u32>(1);
924 rb.Push<u32>(0);
925} 1129}
926 1130
927void Hid::CreateActiveVibrationDeviceList(Kernel::HLERequestContext& ctx) { 1131void Hid::EndPermitVibrationSession(Kernel::HLERequestContext& ctx) {
1132 applet_resource->GetController<Controller_NPad>(HidController::NPad)
1133 .SetPermitVibrationSession(false);
1134
928 LOG_DEBUG(Service_HID, "called"); 1135 LOG_DEBUG(Service_HID, "called");
929 1136
930 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 1137 IPC::ResponseBuilder rb{ctx, 2};
931 rb.Push(RESULT_SUCCESS); 1138 rb.Push(RESULT_SUCCESS);
932 rb.PushIpcInterface<IActiveVibrationDeviceList>();
933} 1139}
934 1140
935void Hid::PermitVibration(Kernel::HLERequestContext& ctx) { 1141void Hid::IsVibrationDeviceMounted(Kernel::HLERequestContext& ctx) {
936 IPC::RequestParser rp{ctx}; 1142 IPC::RequestParser rp{ctx};
937 const auto can_vibrate{rp.Pop<bool>()}; 1143 struct Parameters {
938 Settings::values.vibration_enabled = can_vibrate; 1144 Controller_NPad::DeviceHandle vibration_device_handle{};
1145 INSERT_PADDING_WORDS(1);
1146 u64 applet_resource_user_id{};
1147 };
939 1148
940 LOG_DEBUG(Service_HID, "called, can_vibrate={}", can_vibrate); 1149 const auto parameters{rp.PopRaw<Parameters>()};
941 1150
942 IPC::ResponseBuilder rb{ctx, 2}; 1151 LOG_DEBUG(Service_HID,
943 rb.Push(RESULT_SUCCESS); 1152 "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
944} 1153 parameters.vibration_device_handle.npad_type,
945 1154 parameters.vibration_device_handle.npad_id,
946void Hid::IsVibrationPermitted(Kernel::HLERequestContext& ctx) { 1155 parameters.vibration_device_handle.device_index, parameters.applet_resource_user_id);
947 LOG_DEBUG(Service_HID, "called");
948 1156
949 IPC::ResponseBuilder rb{ctx, 3}; 1157 IPC::ResponseBuilder rb{ctx, 3};
950 rb.Push(RESULT_SUCCESS); 1158 rb.Push(RESULT_SUCCESS);
951 rb.Push(Settings::values.vibration_enabled); 1159 rb.Push(applet_resource->GetController<Controller_NPad>(HidController::NPad)
1160 .IsVibrationDeviceMounted(parameters.vibration_device_handle));
952} 1161}
953 1162
954void Hid::ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) { 1163void Hid::ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) {
@@ -964,11 +1173,19 @@ void Hid::ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) {
964 1173
965void Hid::StartConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) { 1174void Hid::StartConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) {
966 IPC::RequestParser rp{ctx}; 1175 IPC::RequestParser rp{ctx};
967 const auto handle{rp.Pop<u32>()}; 1176 struct Parameters {
968 const auto applet_resource_user_id{rp.Pop<u64>()}; 1177 Controller_NPad::DeviceHandle sixaxis_handle{};
1178 INSERT_PADDING_WORDS(1);
1179 u64 applet_resource_user_id{};
1180 };
969 1181
970 LOG_WARNING(Service_HID, "(STUBBED) called, handle={}, applet_resource_user_id={}", handle, 1182 const auto parameters{rp.PopRaw<Parameters>()};
971 applet_resource_user_id); 1183
1184 LOG_WARNING(
1185 Service_HID,
1186 "(STUBBED) called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
1187 parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
1188 parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
972 1189
973 IPC::ResponseBuilder rb{ctx, 2}; 1190 IPC::ResponseBuilder rb{ctx, 2};
974 rb.Push(RESULT_SUCCESS); 1191 rb.Push(RESULT_SUCCESS);
@@ -976,11 +1193,19 @@ void Hid::StartConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) {
976 1193
977void Hid::StopConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) { 1194void Hid::StopConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) {
978 IPC::RequestParser rp{ctx}; 1195 IPC::RequestParser rp{ctx};
979 const auto handle{rp.Pop<u32>()}; 1196 struct Parameters {
980 const auto applet_resource_user_id{rp.Pop<u64>()}; 1197 Controller_NPad::DeviceHandle sixaxis_handle{};
1198 INSERT_PADDING_WORDS(1);
1199 u64 applet_resource_user_id{};
1200 };
981 1201
982 LOG_WARNING(Service_HID, "(STUBBED) called, handle={}, applet_resource_user_id={}", handle, 1202 const auto parameters{rp.PopRaw<Parameters>()};
983 applet_resource_user_id); 1203
1204 LOG_WARNING(
1205 Service_HID,
1206 "(STUBBED) called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
1207 parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
1208 parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
984 1209
985 IPC::ResponseBuilder rb{ctx, 2}; 1210 IPC::ResponseBuilder rb{ctx, 2};
986 rb.Push(RESULT_SUCCESS); 1211 rb.Push(RESULT_SUCCESS);
diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h
index fd0372b18..c8e4a4b55 100644
--- a/src/core/hle/service/hid/hid.h
+++ b/src/core/hle/service/hid/hid.h
@@ -86,17 +86,15 @@ public:
86 86
87private: 87private:
88 void CreateAppletResource(Kernel::HLERequestContext& ctx); 88 void CreateAppletResource(Kernel::HLERequestContext& ctx);
89 void ActivateXpad(Kernel::HLERequestContext& ctx);
90 void GetXpadIDs(Kernel::HLERequestContext& ctx);
91 void ActivateSixAxisSensor(Kernel::HLERequestContext& ctx);
92 void DeactivateSixAxisSensor(Kernel::HLERequestContext& ctx);
93 void ActivateDebugPad(Kernel::HLERequestContext& ctx); 89 void ActivateDebugPad(Kernel::HLERequestContext& ctx);
94 void ActivateTouchScreen(Kernel::HLERequestContext& ctx); 90 void ActivateTouchScreen(Kernel::HLERequestContext& ctx);
95 void ActivateMouse(Kernel::HLERequestContext& ctx); 91 void ActivateMouse(Kernel::HLERequestContext& ctx);
96 void ActivateKeyboard(Kernel::HLERequestContext& ctx); 92 void ActivateKeyboard(Kernel::HLERequestContext& ctx);
97 void SendKeyboardLockKeyEvent(Kernel::HLERequestContext& ctx); 93 void SendKeyboardLockKeyEvent(Kernel::HLERequestContext& ctx);
98 void ActivateGesture(Kernel::HLERequestContext& ctx); 94 void ActivateXpad(Kernel::HLERequestContext& ctx);
99 void ActivateNpadWithRevision(Kernel::HLERequestContext& ctx); 95 void GetXpadIDs(Kernel::HLERequestContext& ctx);
96 void ActivateSixAxisSensor(Kernel::HLERequestContext& ctx);
97 void DeactivateSixAxisSensor(Kernel::HLERequestContext& ctx);
100 void StartSixAxisSensor(Kernel::HLERequestContext& ctx); 98 void StartSixAxisSensor(Kernel::HLERequestContext& ctx);
101 void StopSixAxisSensor(Kernel::HLERequestContext& ctx); 99 void StopSixAxisSensor(Kernel::HLERequestContext& ctx);
102 void EnableSixAxisSensorFusion(Kernel::HLERequestContext& ctx); 100 void EnableSixAxisSensorFusion(Kernel::HLERequestContext& ctx);
@@ -104,6 +102,7 @@ private:
104 void GetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx); 102 void GetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx);
105 void ResetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx); 103 void ResetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx);
106 void IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx); 104 void IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx);
105 void ActivateGesture(Kernel::HLERequestContext& ctx);
107 void SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx); 106 void SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx);
108 void GetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx); 107 void GetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx);
109 void SetSupportedNpadIdType(Kernel::HLERequestContext& ctx); 108 void SetSupportedNpadIdType(Kernel::HLERequestContext& ctx);
@@ -112,6 +111,7 @@ private:
112 void AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx); 111 void AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx);
113 void DisconnectNpad(Kernel::HLERequestContext& ctx); 112 void DisconnectNpad(Kernel::HLERequestContext& ctx);
114 void GetPlayerLedPattern(Kernel::HLERequestContext& ctx); 113 void GetPlayerLedPattern(Kernel::HLERequestContext& ctx);
114 void ActivateNpadWithRevision(Kernel::HLERequestContext& ctx);
115 void SetNpadJoyHoldType(Kernel::HLERequestContext& ctx); 115 void SetNpadJoyHoldType(Kernel::HLERequestContext& ctx);
116 void GetNpadJoyHoldType(Kernel::HLERequestContext& ctx); 116 void GetNpadJoyHoldType(Kernel::HLERequestContext& ctx);
117 void SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx); 117 void SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx);
@@ -125,15 +125,16 @@ private:
125 void SwapNpadAssignment(Kernel::HLERequestContext& ctx); 125 void SwapNpadAssignment(Kernel::HLERequestContext& ctx);
126 void IsUnintendedHomeButtonInputProtectionEnabled(Kernel::HLERequestContext& ctx); 126 void IsUnintendedHomeButtonInputProtectionEnabled(Kernel::HLERequestContext& ctx);
127 void EnableUnintendedHomeButtonInputProtection(Kernel::HLERequestContext& ctx); 127 void EnableUnintendedHomeButtonInputProtection(Kernel::HLERequestContext& ctx);
128 void BeginPermitVibrationSession(Kernel::HLERequestContext& ctx); 128 void GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx);
129 void EndPermitVibrationSession(Kernel::HLERequestContext& ctx);
130 void SendVibrationValue(Kernel::HLERequestContext& ctx); 129 void SendVibrationValue(Kernel::HLERequestContext& ctx);
131 void SendVibrationValues(Kernel::HLERequestContext& ctx);
132 void GetActualVibrationValue(Kernel::HLERequestContext& ctx); 130 void GetActualVibrationValue(Kernel::HLERequestContext& ctx);
133 void GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx);
134 void CreateActiveVibrationDeviceList(Kernel::HLERequestContext& ctx); 131 void CreateActiveVibrationDeviceList(Kernel::HLERequestContext& ctx);
135 void PermitVibration(Kernel::HLERequestContext& ctx); 132 void PermitVibration(Kernel::HLERequestContext& ctx);
136 void IsVibrationPermitted(Kernel::HLERequestContext& ctx); 133 void IsVibrationPermitted(Kernel::HLERequestContext& ctx);
134 void SendVibrationValues(Kernel::HLERequestContext& ctx);
135 void BeginPermitVibrationSession(Kernel::HLERequestContext& ctx);
136 void EndPermitVibrationSession(Kernel::HLERequestContext& ctx);
137 void IsVibrationDeviceMounted(Kernel::HLERequestContext& ctx);
137 void ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx); 138 void ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx);
138 void StartConsoleSixAxisSensor(Kernel::HLERequestContext& ctx); 139 void StartConsoleSixAxisSensor(Kernel::HLERequestContext& ctx);
139 void StopConsoleSixAxisSensor(Kernel::HLERequestContext& ctx); 140 void StopConsoleSixAxisSensor(Kernel::HLERequestContext& ctx);
@@ -146,6 +147,22 @@ private:
146 void SetIsPalmaAllConnectable(Kernel::HLERequestContext& ctx); 147 void SetIsPalmaAllConnectable(Kernel::HLERequestContext& ctx);
147 void SetPalmaBoostMode(Kernel::HLERequestContext& ctx); 148 void SetPalmaBoostMode(Kernel::HLERequestContext& ctx);
148 149
150 enum class VibrationDeviceType : u32 {
151 LinearResonantActuator = 1,
152 };
153
154 enum class VibrationDevicePosition : u32 {
155 None = 0,
156 Left = 1,
157 Right = 2,
158 };
159
160 struct VibrationDeviceInfo {
161 VibrationDeviceType type{};
162 VibrationDevicePosition position{};
163 };
164 static_assert(sizeof(VibrationDeviceInfo) == 0x8, "VibrationDeviceInfo has incorrect size.");
165
149 std::shared_ptr<IAppletResource> applet_resource; 166 std::shared_ptr<IAppletResource> applet_resource;
150 Core::System& system; 167 Core::System& system;
151}; 168};
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp
index 5b0e371fe..55e00dd93 100644
--- a/src/core/hle/service/vi/vi.cpp
+++ b/src/core/hle/service/vi/vi.cpp
@@ -771,7 +771,7 @@ private:
771 IPC::ResponseBuilder rb{ctx, 6}; 771 IPC::ResponseBuilder rb{ctx, 6};
772 rb.Push(RESULT_SUCCESS); 772 rb.Push(RESULT_SUCCESS);
773 773
774 if (Settings::values.use_docked_mode) { 774 if (Settings::values.use_docked_mode.GetValue()) {
775 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth) * 775 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth) *
776 static_cast<u32>(Settings::values.resolution_factor.GetValue())); 776 static_cast<u32>(Settings::values.resolution_factor.GetValue()));
777 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight) * 777 rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight) *
diff --git a/src/core/settings.cpp b/src/core/settings.cpp
index 0587b9374..aadbc3932 100644
--- a/src/core/settings.cpp
+++ b/src/core/settings.cpp
@@ -49,7 +49,7 @@ void LogSettings() {
49 }; 49 };
50 50
51 LOG_INFO(Config, "yuzu Configuration:"); 51 LOG_INFO(Config, "yuzu Configuration:");
52 log_setting("Controls_UseDockedMode", values.use_docked_mode); 52 log_setting("Controls_UseDockedMode", values.use_docked_mode.GetValue());
53 log_setting("System_RngSeed", values.rng_seed.GetValue().value_or(0)); 53 log_setting("System_RngSeed", values.rng_seed.GetValue().value_or(0));
54 log_setting("System_CurrentUser", values.current_user); 54 log_setting("System_CurrentUser", values.current_user);
55 log_setting("System_LanguageIndex", values.language_index.GetValue()); 55 log_setting("System_LanguageIndex", values.language_index.GetValue());
@@ -145,6 +145,12 @@ void RestoreGlobalState() {
145 values.rng_seed.SetGlobal(true); 145 values.rng_seed.SetGlobal(true);
146 values.custom_rtc.SetGlobal(true); 146 values.custom_rtc.SetGlobal(true);
147 values.sound_index.SetGlobal(true); 147 values.sound_index.SetGlobal(true);
148
149 // Controls
150 values.players.SetGlobal(true);
151 values.use_docked_mode.SetGlobal(true);
152 values.vibration_enabled.SetGlobal(true);
153 values.motion_enabled.SetGlobal(true);
148} 154}
149 155
150void Sanitize() { 156void Sanitize() {
diff --git a/src/core/settings.h b/src/core/settings.h
index 28616a574..476c3fdf3 100644
--- a/src/core/settings.h
+++ b/src/core/settings.h
@@ -65,6 +65,38 @@ private:
65 Type local{}; 65 Type local{};
66}; 66};
67 67
68/**
69 * The InputSetting class allows for getting a reference to either the global or local members.
70 * This is required as we cannot easily modify the values of user-defined types within containers
71 * using the SetValue() member function found in the Setting class. The primary purpose of this
72 * class is to store an array of 10 PlayerInput structs for both the global and local (per-game)
73 * setting and allows for easily accessing and modifying both settings.
74 */
75template <typename Type>
76class InputSetting final {
77public:
78 InputSetting() = default;
79 explicit InputSetting(Type val) : global{val} {}
80 ~InputSetting() = default;
81 void SetGlobal(bool to_global) {
82 use_global = to_global;
83 }
84 bool UsingGlobal() const {
85 return use_global;
86 }
87 Type& GetValue(bool need_global = false) {
88 if (use_global || need_global) {
89 return global;
90 }
91 return local;
92 }
93
94private:
95 bool use_global = true;
96 Type global{};
97 Type local{};
98};
99
68struct TouchFromButtonMap { 100struct TouchFromButtonMap {
69 std::string name; 101 std::string name;
70 std::vector<std::string> buttons; 102 std::vector<std::string> buttons;
@@ -133,9 +165,18 @@ struct Values {
133 Setting<s32> sound_index; 165 Setting<s32> sound_index;
134 166
135 // Controls 167 // Controls
136 std::array<PlayerInput, 10> players; 168 InputSetting<std::array<PlayerInput, 10>> players;
169
170 Setting<bool> use_docked_mode;
137 171
138 bool use_docked_mode; 172 Setting<bool> vibration_enabled;
173 Setting<bool> enable_accurate_vibrations;
174
175 Setting<bool> motion_enabled;
176 std::string motion_device;
177 std::string udp_input_address;
178 u16 udp_input_port;
179 u8 udp_pad_index;
139 180
140 bool mouse_enabled; 181 bool mouse_enabled;
141 std::string mouse_device; 182 std::string mouse_device;
@@ -149,20 +190,15 @@ struct Values {
149 ButtonsRaw debug_pad_buttons; 190 ButtonsRaw debug_pad_buttons;
150 AnalogsRaw debug_pad_analogs; 191 AnalogsRaw debug_pad_analogs;
151 192
152 bool vibration_enabled;
153
154 bool motion_enabled;
155 std::string motion_device;
156 std::string touch_device;
157 TouchscreenInput touchscreen; 193 TouchscreenInput touchscreen;
158 std::atomic_bool is_device_reload_pending{true}; 194
159 bool use_touch_from_button; 195 bool use_touch_from_button;
196 std::string touch_device;
160 int touch_from_button_map_index; 197 int touch_from_button_map_index;
161 std::string udp_input_address;
162 u16 udp_input_port;
163 u8 udp_pad_index;
164 std::vector<TouchFromButtonMap> touch_from_button_maps; 198 std::vector<TouchFromButtonMap> touch_from_button_maps;
165 199
200 std::atomic_bool is_device_reload_pending{true};
201
166 // Data Storage 202 // Data Storage
167 bool use_virtual_sd; 203 bool use_virtual_sd;
168 bool gamecard_inserted; 204 bool gamecard_inserted;
diff --git a/src/core/telemetry_session.cpp b/src/core/telemetry_session.cpp
index ebc19e18a..e0908186b 100644
--- a/src/core/telemetry_session.cpp
+++ b/src/core/telemetry_session.cpp
@@ -213,7 +213,7 @@ void TelemetrySession::AddInitialInfo(Loader::AppLoader& app_loader) {
213 Settings::values.use_assembly_shaders.GetValue()); 213 Settings::values.use_assembly_shaders.GetValue());
214 AddField(field_type, "Renderer_UseAsynchronousShaders", 214 AddField(field_type, "Renderer_UseAsynchronousShaders",
215 Settings::values.use_asynchronous_shaders.GetValue()); 215 Settings::values.use_asynchronous_shaders.GetValue());
216 AddField(field_type, "System_UseDockedMode", Settings::values.use_docked_mode); 216 AddField(field_type, "System_UseDockedMode", Settings::values.use_docked_mode.GetValue());
217} 217}
218 218
219bool TelemetrySession::SubmitTestcase() { 219bool TelemetrySession::SubmitTestcase() {