diff --git a/Ryujinx.HLE/HOS/Services/Hid/HidDevices/NpadDevices.cs b/Ryujinx.HLE/HOS/Services/Hid/HidDevices/NpadDevices.cs index a063b41fdb..bbc30172c0 100644 --- a/Ryujinx.HLE/HOS/Services/Hid/HidDevices/NpadDevices.cs +++ b/Ryujinx.HLE/HOS/Services/Hid/HidDevices/NpadDevices.cs @@ -569,7 +569,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid UpdateUnusedSixInputIfNotEqual(ref lifo, ref currentNpad.JoyRightSixAxisSensor); } - if (!needUpdateRight) + if (!needUpdateRight && !isRightPair) { SixAxisSensorState emptyState = new SixAxisSensorState(); diff --git a/Ryujinx.Input/HLE/NpadController.cs b/Ryujinx.Input/HLE/NpadController.cs index e1a8e2d753..701d76c1f7 100644 --- a/Ryujinx.Input/HLE/NpadController.cs +++ b/Ryujinx.Input/HLE/NpadController.cs @@ -208,7 +208,8 @@ namespace Ryujinx.Input.HLE private bool _isValid; private string _id; - private MotionInput _motionInput; + private MotionInput _leftMotionInput; + private MotionInput _rightMotionInput; private IGamepad _gamepad; private InputConfig _config; @@ -259,7 +260,7 @@ namespace Ryujinx.Input.HLE else { // Non-controller doesn't have motions. - _motionInput = null; + _leftMotionInput = null; } _config = config; @@ -274,11 +275,11 @@ namespace Ryujinx.Input.HLE { if (motionConfig.MotionBackend != MotionInputBackendType.CemuHook) { - _motionInput = new MotionInput(); + _leftMotionInput = new MotionInput(); } else { - _motionInput = null; + _leftMotionInput = null; } } @@ -300,7 +301,12 @@ namespace Ryujinx.Input.HLE accelerometer = new Vector3(accelerometer.X, -accelerometer.Z, accelerometer.Y); gyroscope = new Vector3(gyroscope.X, gyroscope.Z, gyroscope.Y); - _motionInput.Update(accelerometer, gyroscope, (ulong)PerformanceCounter.ElapsedNanoseconds / 1000, controllerConfig.Motion.Sensitivity, (float)controllerConfig.Motion.GyroDeadzone); + _leftMotionInput.Update(accelerometer, gyroscope, (ulong)PerformanceCounter.ElapsedNanoseconds / 1000, controllerConfig.Motion.Sensitivity, (float)controllerConfig.Motion.GyroDeadzone); + + if (controllerConfig.ControllerType == ConfigControllerType.JoyconPair) + { + _rightMotionInput = _leftMotionInput; + } } } else if (controllerConfig.Motion.MotionBackend == MotionInputBackendType.CemuHook && controllerConfig.Motion is CemuHookMotionConfigController cemuControllerConfig) @@ -310,16 +316,22 @@ namespace Ryujinx.Input.HLE // First of all ensure we are registered _cemuHookClient.RegisterClient(clientId, cemuControllerConfig.DsuServerHost, cemuControllerConfig.DsuServerPort); - // Then request data + // Then request and retrieve the data _cemuHookClient.RequestData(clientId, cemuControllerConfig.Slot); + _cemuHookClient.TryGetData(clientId, cemuControllerConfig.Slot, out _leftMotionInput); - if (controllerConfig.ControllerType == ConfigControllerType.JoyconPair && !cemuControllerConfig.MirrorInput) + if (controllerConfig.ControllerType == ConfigControllerType.JoyconPair) { - _cemuHookClient.RequestData(clientId, cemuControllerConfig.AltSlot); + if (!cemuControllerConfig.MirrorInput) + { + _cemuHookClient.RequestData(clientId, cemuControllerConfig.AltSlot); + _cemuHookClient.TryGetData(clientId, cemuControllerConfig.AltSlot, out _rightMotionInput); + } + else + { + _rightMotionInput = _leftMotionInput; + } } - - // Finally, get motion input data - _cemuHookClient.TryGetData(clientId, cemuControllerConfig.Slot, out _motionInput); } } } @@ -327,7 +339,7 @@ namespace Ryujinx.Input.HLE { // Reset states State = default; - _motionInput = null; + _leftMotionInput = null; } } @@ -395,20 +407,32 @@ namespace Ryujinx.Input.HLE return state; } - public SixAxisInput GetHLEMotionState() + public SixAxisInput GetHLEMotionState(bool isJoyconRightPair = false) { float[] orientationForHLE = new float[9]; Vector3 gyroscope; Vector3 accelerometer; Vector3 rotation; - if (_motionInput != null) - { - gyroscope = Truncate(_motionInput.Gyroscrope * 0.0027f, 3); - accelerometer = Truncate(_motionInput.Accelerometer, 3); - rotation = Truncate(_motionInput.Rotation * 0.0027f, 3); + MotionInput motionInput = _leftMotionInput; - Matrix4x4 orientation = _motionInput.GetOrientation(); + if (isJoyconRightPair) + { + if (_rightMotionInput == null) + { + return default; + } + + motionInput = _rightMotionInput; + } + + if (motionInput != null) + { + gyroscope = Truncate(motionInput.Gyroscrope * 0.0027f, 3); + accelerometer = Truncate(motionInput.Accelerometer, 3); + rotation = Truncate(motionInput.Rotation * 0.0027f, 3); + + Matrix4x4 orientation = motionInput.GetOrientation(); orientationForHLE[0] = Math.Clamp(orientation.M11, -1f, 1f); orientationForHLE[1] = Math.Clamp(orientation.M12, -1f, 1f); diff --git a/Ryujinx.Input/HLE/NpadManager.cs b/Ryujinx.Input/HLE/NpadManager.cs index c46f80b0e3..03bde64b7e 100644 --- a/Ryujinx.Input/HLE/NpadManager.cs +++ b/Ryujinx.Input/HLE/NpadManager.cs @@ -1,5 +1,6 @@ using Ryujinx.Common.Configuration.Hid; using Ryujinx.Common.Configuration.Hid.Controller; +using Ryujinx.Common.Configuration.Hid.Controller.Motion; using Ryujinx.Common.Configuration.Hid.Keyboard; using Ryujinx.HLE.HOS.Services.Hid; using System; @@ -163,10 +164,12 @@ namespace Ryujinx.Input.HLE foreach (InputConfig inputConfig in _inputConfig) { GamepadInput inputState = default; - SixAxisInput motionState = default; + (SixAxisInput, SixAxisInput) motionState = default; NpadController controller = _controllers[(int)inputConfig.PlayerIndex]; + bool isJoyconPair = false; + // Do we allow input updates and is a controller connected? if (!_blockInputUpdates && controller != null) { @@ -179,7 +182,11 @@ namespace Ryujinx.Input.HLE inputState.Buttons |= _device.Hid.UpdateStickButtons(inputState.LStick, inputState.RStick); - motionState = controller.GetHLEMotionState(); + isJoyconPair = inputConfig.ControllerType == Common.Configuration.Hid.ControllerType.JoyconPair; + + var altMotionState = isJoyconPair ? controller.GetHLEMotionState(true) : default; + + motionState = (controller.GetHLEMotionState(), altMotionState); if (_enableKeyboard) { @@ -189,14 +196,21 @@ namespace Ryujinx.Input.HLE else { // Ensure that orientation isn't null - motionState.Orientation = new float[9]; + motionState.Item1.Orientation = new float[9]; } inputState.PlayerId = (Ryujinx.HLE.HOS.Services.Hid.PlayerIndex)inputConfig.PlayerIndex; - motionState.PlayerId = (Ryujinx.HLE.HOS.Services.Hid.PlayerIndex)inputConfig.PlayerIndex; + motionState.Item1.PlayerId = (Ryujinx.HLE.HOS.Services.Hid.PlayerIndex)inputConfig.PlayerIndex; hleInputStates.Add(inputState); - hleMotionStates.Add(motionState); + hleMotionStates.Add(motionState.Item1); + + if (isJoyconPair && !motionState.Item2.Equals(default)) + { + motionState.Item2.PlayerId = (Ryujinx.HLE.HOS.Services.Hid.PlayerIndex)inputConfig.PlayerIndex; + + hleMotionStates.Add(motionState.Item2); + } } _device.Hid.Npads.Update(hleInputStates);