From 472210bf72e1509f7266e49bf50be7a681078552 Mon Sep 17 00:00:00 2001
From: David Marcec <dmarcecguzman@gmail.com>
Date: Mon, 1 Jul 2019 15:12:57 +1000
Subject: [PATCH 1/2] hid:StartLrAssignmentMode, hid:StopLrAssignmentMode,
 hid:SwapNpadAssignment

StartLrAssignmentMode and StopLrAssignmentMode don't require any implementation as it's just used for showing the screen of changing the controller orientation if the user wishes to do so.  Ever since #1634 this has not been needed as users can specify the controller orientation from the config and swap at any time. We store a private member just in case this gets used for anything extra in the future
---
 src/core/CMakeLists.txt                       |  1 +
 src/core/hle/service/hid/controllers/npad.cpp | 30 +++++++++++
 src/core/hle/service/hid/controllers/npad.h   |  5 ++
 src/core/hle/service/hid/errors.h             | 13 +++++
 src/core/hle/service/hid/hid.cpp              | 50 +++++++++++++++++--
 src/core/hle/service/hid/hid.h                |  3 ++
 6 files changed, 99 insertions(+), 3 deletions(-)
 create mode 100644 src/core/hle/service/hid/errors.h

diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index cb77b99eea..7439018d90 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -291,6 +291,7 @@ add_library(core STATIC
     hle/service/hid/irs.h
     hle/service/hid/xcd.cpp
     hle/service/hid/xcd.h
+    hle/service/hid/errors.h
     hle/service/hid/controllers/controller_base.cpp
     hle/service/hid/controllers/controller_base.h
     hle/service/hid/controllers/debug_pad.cpp
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index fdd6d79a26..99af0469d8 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -548,6 +548,36 @@ void Controller_NPad::DisconnectNPad(u32 npad_id) {
     connected_controllers[NPadIdToIndex(npad_id)].is_connected = false;
 }
 
+void Controller_NPad::StartLRAssignmentMode() {
+    // Nothing internally is used for lr assignment mode. Since we have the ability to set the
+    // controller types from boot, it doesn't really matter about showing a selection screen
+    is_in_lr_assignment_mode = true;
+}
+
+void Controller_NPad::StopLRAssignmentMode() {
+    is_in_lr_assignment_mode = false;
+}
+
+bool Controller_NPad::SwapNpadAssignment(u32 npad_id_1, u32 npad_id_2) {
+    if (npad_id_1 == NPAD_HANDHELD || npad_id_2 == NPAD_HANDHELD || npad_id_1 == NPAD_UNKNOWN ||
+        npad_id_2 == NPAD_UNKNOWN) {
+        return true;
+    }
+
+    if (!IsControllerSupported(connected_controllers[NPadIdToIndex(npad_id_1)].type) ||
+        !IsControllerSupported(connected_controllers[NPadIdToIndex(npad_id_2)].type)) {
+        return false;
+    }
+
+    std::swap(connected_controllers[NPadIdToIndex(npad_id_1)].type,
+              connected_controllers[NPadIdToIndex(npad_id_2)].type);
+
+    InitNewlyAddedControler(NPadIdToIndex(npad_id_1));
+    InitNewlyAddedControler(NPadIdToIndex(npad_id_2));
+
+    return true;
+}
+
 bool Controller_NPad::IsControllerSupported(NPadControllerType controller) {
     if (controller == NPadControllerType::Handheld) {
         // Handheld is not even a supported type, lets stop here
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h
index 4ff50b3cd6..4b6c1083fb 100644
--- a/src/core/hle/service/hid/controllers/npad.h
+++ b/src/core/hle/service/hid/controllers/npad.h
@@ -124,6 +124,10 @@ public:
     void ConnectAllDisconnectedControllers();
     void ClearAllControllers();
 
+    void StartLRAssignmentMode();
+    void StopLRAssignmentMode();
+    bool SwapNpadAssignment(u32 npad_id_1, u32 npad_id_2);
+
     // Logical OR for all buttons presses on all controllers
     // Specifically for cheat engine and other features.
     u32 GetAndResetPressState();
@@ -321,5 +325,6 @@ private:
     void RequestPadStateUpdate(u32 npad_id);
     std::array<ControllerPad, 10> npad_pad_states{};
     bool IsControllerSupported(NPadControllerType controller);
+    bool is_in_lr_assignment_mode{false};
 };
 } // namespace Service::HID
diff --git a/src/core/hle/service/hid/errors.h b/src/core/hle/service/hid/errors.h
new file mode 100644
index 0000000000..3583642e71
--- /dev/null
+++ b/src/core/hle/service/hid/errors.h
@@ -0,0 +1,13 @@
+// Copyright 2019 yuzu emulator team
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/result.h"
+
+namespace Service::HID {
+
+constexpr ResultCode ERR_NPAD_NOT_CONNECTED{ErrorModule::HID, 710};
+
+} // namespace Service::HID
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index a4ad95d96c..0bd24b8eb1 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -16,6 +16,7 @@
 #include "core/hle/kernel/readable_event.h"
 #include "core/hle/kernel/shared_memory.h"
 #include "core/hle/kernel/writable_event.h"
+#include "core/hle/service/hid/errors.h"
 #include "core/hle/service/hid/hid.h"
 #include "core/hle/service/hid/irs.h"
 #include "core/hle/service/hid/xcd.h"
@@ -202,11 +203,11 @@ Hid::Hid() : ServiceFramework("hid") {
         {123, nullptr, "SetNpadJoyAssignmentModeSingleByDefault"},
         {124, &Hid::SetNpadJoyAssignmentModeDual, "SetNpadJoyAssignmentModeDual"},
         {125, &Hid::MergeSingleJoyAsDualJoy, "MergeSingleJoyAsDualJoy"},
-        {126, nullptr, "StartLrAssignmentMode"},
-        {127, nullptr, "StopLrAssignmentMode"},
+        {126, &Hid::StartLrAssignmentMode, "StartLrAssignmentMode"},
+        {127, &Hid::StopLrAssignmentMode, "StopLrAssignmentMode"},
         {128, &Hid::SetNpadHandheldActivationMode, "SetNpadHandheldActivationMode"},
         {129, nullptr, "GetNpadHandheldActivationMode"},
-        {130, nullptr, "SwapNpadAssignment"},
+        {130, &Hid::SwapNpadAssignment, "SwapNpadAssignment"},
         {131, nullptr, "IsUnintendedHomeButtonInputProtectionEnabled"},
         {132, nullptr, "EnableUnintendedHomeButtonInputProtection"},
         {133, nullptr, "SetNpadJoyAssignmentModeSingleWithDestination"},
@@ -733,6 +734,49 @@ void Hid::SetPalmaBoostMode(Kernel::HLERequestContext& ctx) {
     rb.Push(RESULT_SUCCESS);
 }
 
+void Hid::StartLrAssignmentMode(Kernel::HLERequestContext& ctx) {
+    IPC::RequestParser rp{ctx};
+    const auto applet_resource_user_id{rp.Pop<u64>()};
+
+    LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
+    auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
+    controller.StartLRAssignmentMode();
+
+    IPC::ResponseBuilder rb{ctx, 2};
+    rb.Push(RESULT_SUCCESS);
+}
+
+void Hid::StopLrAssignmentMode(Kernel::HLERequestContext& ctx) {
+    IPC::RequestParser rp{ctx};
+    const auto applet_resource_user_id{rp.Pop<u64>()};
+
+    LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
+    auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
+    controller.StopLRAssignmentMode();
+
+    IPC::ResponseBuilder rb{ctx, 2};
+    rb.Push(RESULT_SUCCESS);
+}
+
+void Hid::SwapNpadAssignment(Kernel::HLERequestContext& ctx) {
+    IPC::RequestParser rp{ctx};
+    const auto npad_1{rp.Pop<u32>()};
+    const auto npad_2{rp.Pop<u32>()};
+    const auto applet_resource_user_id{rp.Pop<u64>()};
+
+    LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, npad_1={}, npad_2={}",
+              applet_resource_user_id, npad_1, npad_2);
+
+    auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad);
+    IPC::ResponseBuilder rb{ctx, 2};
+    if (controller.SwapNpadAssignment(npad_1, npad_2)) {
+        rb.Push(RESULT_SUCCESS);
+    } else {
+        LOG_ERROR(Service_HID, "Npads are not connected!");
+        rb.Push(ERR_NPAD_NOT_CONNECTED);
+    }
+}
+
 class HidDbg final : public ServiceFramework<HidDbg> {
 public:
     explicit HidDbg() : ServiceFramework{"hid:dbg"} {
diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h
index d3660cad2f..28260ef1b8 100644
--- a/src/core/hle/service/hid/hid.h
+++ b/src/core/hle/service/hid/hid.h
@@ -119,6 +119,9 @@ private:
     void StopSixAxisSensor(Kernel::HLERequestContext& ctx);
     void SetIsPalmaAllConnectable(Kernel::HLERequestContext& ctx);
     void SetPalmaBoostMode(Kernel::HLERequestContext& ctx);
+    void StartLrAssignmentMode(Kernel::HLERequestContext& ctx);
+    void StopLrAssignmentMode(Kernel::HLERequestContext& ctx);
+    void SwapNpadAssignment(Kernel::HLERequestContext& ctx);
 
     std::shared_ptr<IAppletResource> applet_resource;
 };

From 5234e08a0d3d4630ee02acae3b85d2e2e65761b5 Mon Sep 17 00:00:00 2001
From: David Marcec <dmarcecguzman@gmail.com>
Date: Mon, 8 Jul 2019 14:51:40 +1000
Subject: [PATCH 2/2] addressed issues

---
 src/core/hle/service/hid/controllers/npad.cpp | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index 99af0469d8..1e81f776f0 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -563,17 +563,18 @@ bool Controller_NPad::SwapNpadAssignment(u32 npad_id_1, u32 npad_id_2) {
         npad_id_2 == NPAD_UNKNOWN) {
         return true;
     }
+    const auto npad_index_1 = NPadIdToIndex(npad_id_1);
+    const auto npad_index_2 = NPadIdToIndex(npad_id_2);
 
-    if (!IsControllerSupported(connected_controllers[NPadIdToIndex(npad_id_1)].type) ||
-        !IsControllerSupported(connected_controllers[NPadIdToIndex(npad_id_2)].type)) {
+    if (!IsControllerSupported(connected_controllers[npad_index_1].type) ||
+        !IsControllerSupported(connected_controllers[npad_index_2].type)) {
         return false;
     }
 
-    std::swap(connected_controllers[NPadIdToIndex(npad_id_1)].type,
-              connected_controllers[NPadIdToIndex(npad_id_2)].type);
+    std::swap(connected_controllers[npad_index_1].type, connected_controllers[npad_index_2].type);
 
-    InitNewlyAddedControler(NPadIdToIndex(npad_id_1));
-    InitNewlyAddedControler(NPadIdToIndex(npad_id_2));
+    InitNewlyAddedControler(npad_index_1);
+    InitNewlyAddedControler(npad_index_2);
 
     return true;
 }