Explorar o código

service: hid: Implement MergeSingleJoyAsDualJoy according to RE

german77 %!s(int64=4) %!d(string=hai) anos
pai
achega
3cf15af31e

+ 50 - 61
src/core/hle/service/hid/controllers/npad.cpp

@@ -1275,77 +1275,66 @@ ResultCode Controller_NPad::GetSixAxisFusionParameters(
     return ResultSuccess;
 }
 
-void Controller_NPad::MergeSingleJoyAsDualJoy(Core::HID::NpadIdType npad_id_1,
-                                              Core::HID::NpadIdType npad_id_2) {
+ResultCode Controller_NPad::MergeSingleJoyAsDualJoy(Core::HID::NpadIdType npad_id_1,
+                                                    Core::HID::NpadIdType npad_id_2) {
     if (!IsNpadIdValid(npad_id_1) || !IsNpadIdValid(npad_id_2)) {
         LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id_1:{}, npad_id_2:{}", npad_id_1,
                   npad_id_2);
-        return;
+        return InvalidNpadId;
     }
     auto& controller_1 = GetControllerFromNpadIdType(npad_id_1);
     auto& controller_2 = GetControllerFromNpadIdType(npad_id_2);
-    const auto controller_style_1 = controller_1.device->GetNpadStyleIndex();
-    const auto controller_style_2 = controller_2.device->GetNpadStyleIndex();
-    bool merge_controllers = false;
+    auto controller_style_1 = controller_1.device->GetNpadStyleIndex();
+    auto controller_style_2 = controller_2.device->GetNpadStyleIndex();
+
+    // Simplify this code by converting dualjoycon with only a side connected to single joycons
+    if (controller_style_1 == Core::HID::NpadStyleIndex::JoyconDual) {
+        if (controller_1.is_dual_left_connected && !controller_1.is_dual_right_connected) {
+            controller_style_1 = Core::HID::NpadStyleIndex::JoyconLeft;
+        }
+        if (!controller_1.is_dual_left_connected && controller_1.is_dual_right_connected) {
+            controller_style_1 = Core::HID::NpadStyleIndex::JoyconRight;
+        }
+    }
+    if (controller_style_2 == Core::HID::NpadStyleIndex::JoyconDual) {
+        if (controller_2.is_dual_left_connected && !controller_2.is_dual_right_connected) {
+            controller_style_2 = Core::HID::NpadStyleIndex::JoyconLeft;
+        }
+        if (!controller_2.is_dual_left_connected && controller_2.is_dual_right_connected) {
+            controller_style_2 = Core::HID::NpadStyleIndex::JoyconRight;
+        }
+    }
 
-    // If the controllers at both npad indices form a pair of left and right joycons, merge them.
-    // Otherwise, do nothing.
+    // Invalid merge errors
+    if (controller_style_1 == Core::HID::NpadStyleIndex::JoyconDual ||
+        controller_style_2 == Core::HID::NpadStyleIndex::JoyconDual) {
+        return NpadIsDualJoycon;
+    }
     if (controller_style_1 == Core::HID::NpadStyleIndex::JoyconLeft &&
+        controller_style_2 == Core::HID::NpadStyleIndex::JoyconLeft) {
+        return NpadIsSameType;
+    }
+    if (controller_style_1 == Core::HID::NpadStyleIndex::JoyconRight &&
         controller_style_2 == Core::HID::NpadStyleIndex::JoyconRight) {
-        merge_controllers = true;
-    }
-    if (controller_style_2 == Core::HID::NpadStyleIndex::JoyconLeft &&
-        controller_style_1 == Core::HID::NpadStyleIndex::JoyconRight) {
-        merge_controllers = true;
-    }
-    if (controller_style_1 == Core::HID::NpadStyleIndex::JoyconDual &&
-        controller_style_2 == Core::HID::NpadStyleIndex::JoyconRight &&
-        controller_1.is_dual_left_connected && !controller_1.is_dual_right_connected) {
-        merge_controllers = true;
-    }
-    if (controller_style_1 == Core::HID::NpadStyleIndex::JoyconDual &&
-        controller_style_2 == Core::HID::NpadStyleIndex::JoyconLeft &&
-        !controller_1.is_dual_left_connected && controller_1.is_dual_right_connected) {
-        merge_controllers = true;
-    }
-    if (controller_style_2 == Core::HID::NpadStyleIndex::JoyconDual &&
-        controller_style_1 == Core::HID::NpadStyleIndex::JoyconRight &&
-        controller_2.is_dual_left_connected && !controller_2.is_dual_right_connected) {
-        merge_controllers = true;
-    }
-    if (controller_style_2 == Core::HID::NpadStyleIndex::JoyconDual &&
-        controller_style_1 == Core::HID::NpadStyleIndex::JoyconLeft &&
-        !controller_2.is_dual_left_connected && controller_2.is_dual_right_connected) {
-        merge_controllers = true;
-    }
-    if (controller_style_1 == Core::HID::NpadStyleIndex::JoyconDual &&
-        controller_style_2 == Core::HID::NpadStyleIndex::JoyconDual &&
-        controller_1.is_dual_left_connected && !controller_1.is_dual_right_connected &&
-        !controller_2.is_dual_left_connected && controller_2.is_dual_right_connected) {
-        merge_controllers = true;
-    }
-    if (controller_style_1 == Core::HID::NpadStyleIndex::JoyconDual &&
-        controller_style_2 == Core::HID::NpadStyleIndex::JoyconDual &&
-        !controller_1.is_dual_left_connected && controller_1.is_dual_right_connected &&
-        controller_2.is_dual_left_connected && !controller_2.is_dual_right_connected) {
-        merge_controllers = true;
-    }
-
-    if (merge_controllers) {
-        // Disconnect the joycon at the second id and connect the dual joycon at the first index.
-        DisconnectNpad(npad_id_2);
-        controller_1.is_dual_left_connected = true;
-        controller_1.is_dual_right_connected = true;
-        AddNewControllerAt(Core::HID::NpadStyleIndex::JoyconDual, npad_id_1);
-        return;
+        return NpadIsSameType;
+    }
+
+    // These exceptions are handled as if they where dual joycon
+    if (controller_style_1 != Core::HID::NpadStyleIndex::JoyconLeft &&
+        controller_style_1 != Core::HID::NpadStyleIndex::JoyconRight) {
+        return NpadIsDualJoycon;
+    }
+    if (controller_style_2 != Core::HID::NpadStyleIndex::JoyconLeft &&
+        controller_style_2 != Core::HID::NpadStyleIndex::JoyconRight) {
+        return NpadIsDualJoycon;
     }
-    LOG_WARNING(Service_HID,
-                "Controllers can't be merged npad_id_1:{}, npad_id_2:{}, type_1:{}, type_2:{}, "
-                "dual_1(left/right):{}/{}, dual_2(left/right):{}/{}",
-                npad_id_1, npad_id_2, controller_1.device->GetNpadStyleIndex(),
-                controller_2.device->GetNpadStyleIndex(), controller_1.is_dual_left_connected,
-                controller_1.is_dual_right_connected, controller_2.is_dual_left_connected,
-                controller_2.is_dual_right_connected);
+
+    // Disconnect the joycon at the second id and connect the dual joycon at the first index.
+    DisconnectNpad(npad_id_2);
+    controller_1.is_dual_left_connected = true;
+    controller_1.is_dual_right_connected = true;
+    AddNewControllerAt(Core::HID::NpadStyleIndex::JoyconDual, npad_id_1);
+    return ResultSuccess;
 }
 
 void Controller_NPad::StartLRAssignmentMode() {

+ 2 - 1
src/core/hle/service/hid/controllers/npad.h

@@ -174,7 +174,8 @@ public:
     void ConnectAllDisconnectedControllers();
     void ClearAllControllers();
 
-    void MergeSingleJoyAsDualJoy(Core::HID::NpadIdType npad_id_1, Core::HID::NpadIdType npad_id_2);
+    ResultCode MergeSingleJoyAsDualJoy(Core::HID::NpadIdType npad_id_1,
+                                       Core::HID::NpadIdType npad_id_2);
     void StartLRAssignmentMode();
     void StopLRAssignmentMode();
     ResultCode SwapNpadAssignment(Core::HID::NpadIdType npad_id_1, Core::HID::NpadIdType npad_id_2);

+ 2 - 0
src/core/hle/service/hid/errors.h

@@ -9,6 +9,8 @@ namespace Service::HID {
 
 constexpr ResultCode NpadInvalidHandle{ErrorModule::HID, 100};
 constexpr ResultCode InvalidSixAxisFusionRange{ErrorModule::HID, 423};
+constexpr ResultCode NpadIsDualJoycon{ErrorModule::HID, 601};
+constexpr ResultCode NpadIsSameType{ErrorModule::HID, 602};
 constexpr ResultCode InvalidNpadId{ErrorModule::HID, 709};
 constexpr ResultCode NpadNotConnected{ErrorModule::HID, 710};
 

+ 3 - 3
src/core/hle/service/hid/hid.cpp

@@ -1090,14 +1090,14 @@ void Hid::MergeSingleJoyAsDualJoy(Kernel::HLERequestContext& ctx) {
     const auto npad_id_2{rp.PopEnum<Core::HID::NpadIdType>()};
     const auto applet_resource_user_id{rp.Pop<u64>()};
 
-    applet_resource->GetController<Controller_NPad>(HidController::NPad)
-        .MergeSingleJoyAsDualJoy(npad_id_1, npad_id_2);
+    auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad);
+    const auto result = controller.MergeSingleJoyAsDualJoy(npad_id_1, npad_id_2);
 
     LOG_DEBUG(Service_HID, "called, npad_id_1={}, npad_id_2={}, applet_resource_user_id={}",
               npad_id_1, npad_id_2, applet_resource_user_id);
 
     IPC::ResponseBuilder rb{ctx, 2};
-    rb.Push(ResultSuccess);
+    rb.Push(result);
 }
 
 void Hid::StartLrAssignmentMode(Kernel::HLERequestContext& ctx) {