hid: Various fixes and cleanup (#3326)

* hid: Various fix and cleanup

* Add IsValidNpadIdType

* remove ()
This commit is contained in:
Ac_K 2022-05-08 00:28:54 +02:00 committed by GitHub
parent 50d7ecf76d
commit 92ca1cb0cb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 147 additions and 123 deletions

View file

@ -15,7 +15,6 @@ using Ryujinx.HLE.HOS.Kernel.Threading;
using Ryujinx.HLE.HOS.Services.Am.AppletAE.Storage; using Ryujinx.HLE.HOS.Services.Am.AppletAE.Storage;
using Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.ApplicationProxy.Types; using Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.ApplicationProxy.Types;
using Ryujinx.HLE.HOS.Services.Sdb.Pdm.QueryService; using Ryujinx.HLE.HOS.Services.Sdb.Pdm.QueryService;
using Ryujinx.HLE.HOS.Services.Sm;
using Ryujinx.HLE.HOS.SystemState; using Ryujinx.HLE.HOS.SystemState;
using System; using System;
using System.Numerics; using System.Numerics;
@ -42,6 +41,8 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
private int _notificationStorageChannelEventHandle; private int _notificationStorageChannelEventHandle;
private int _healthWarningDisappearedSystemEventHandle; private int _healthWarningDisappearedSystemEventHandle;
private bool _gamePlayRecordingState;
private int _jitLoaded; private int _jitLoaded;
private HorizonClient _horizon; private HorizonClient _horizon;
@ -349,6 +350,15 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
return ResultCode.Success; return ResultCode.Success;
} }
[CommandHipc(65)] // 3.0.0+
// IsGamePlayRecordingSupported() -> u8
public ResultCode IsGamePlayRecordingSupported(ServiceCtx context)
{
context.ResponseData.Write(_gamePlayRecordingState);
return ResultCode.Success;
}
[CommandHipc(66)] // 3.0.0+ [CommandHipc(66)] // 3.0.0+
// InitializeGamePlayRecording(u64, handle<copy>) // InitializeGamePlayRecording(u64, handle<copy>)
public ResultCode InitializeGamePlayRecording(ServiceCtx context) public ResultCode InitializeGamePlayRecording(ServiceCtx context)
@ -362,9 +372,9 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
// SetGamePlayRecordingState(u32) // SetGamePlayRecordingState(u32)
public ResultCode SetGamePlayRecordingState(ServiceCtx context) public ResultCode SetGamePlayRecordingState(ServiceCtx context)
{ {
int state = context.RequestData.ReadInt32(); _gamePlayRecordingState = context.RequestData.ReadInt32() != 0;
Logger.Stub?.PrintStub(LogClass.ServiceAm, new { state }); Logger.Stub?.PrintStub(LogClass.ServiceAm, new { _gamePlayRecordingState });
return ResultCode.Success; return ResultCode.Success;
} }

View file

@ -21,7 +21,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
private ControllerType[] _configuredTypes; private ControllerType[] _configuredTypes;
private KEvent[] _styleSetUpdateEvents; private KEvent[] _styleSetUpdateEvents;
private bool[] _supportedPlayers; private bool[] _supportedPlayers;
private static HidVibrationValue _neutralVibrationValue = new HidVibrationValue private static VibrationValue _neutralVibrationValue = new VibrationValue
{ {
AmplitudeLow = 0f, AmplitudeLow = 0f,
FrequencyLow = 160f, FrequencyLow = 160f,
@ -33,8 +33,8 @@ namespace Ryujinx.HLE.HOS.Services.Hid
internal bool SixAxisActive = false; // TODO: link to hidserver when implemented internal bool SixAxisActive = false; // TODO: link to hidserver when implemented
internal ControllerType SupportedStyleSets { get; set; } internal ControllerType SupportedStyleSets { get; set; }
public Dictionary<PlayerIndex, ConcurrentQueue<(HidVibrationValue, HidVibrationValue)>> RumbleQueues = new Dictionary<PlayerIndex, ConcurrentQueue<(HidVibrationValue, HidVibrationValue)>>(); public Dictionary<PlayerIndex, ConcurrentQueue<(VibrationValue, VibrationValue)>> RumbleQueues = new Dictionary<PlayerIndex, ConcurrentQueue<(VibrationValue, VibrationValue)>>();
public Dictionary<PlayerIndex, (HidVibrationValue, HidVibrationValue)> LastVibrationValues = new Dictionary<PlayerIndex, (HidVibrationValue, HidVibrationValue)>(); public Dictionary<PlayerIndex, (VibrationValue, VibrationValue)> LastVibrationValues = new Dictionary<PlayerIndex, (VibrationValue, VibrationValue)>();
public NpadDevices(Switch device, bool active = true) : base(device, active) public NpadDevices(Switch device, bool active = true) : base(device, active)
{ {
@ -588,21 +588,21 @@ namespace Ryujinx.HLE.HOS.Services.Hid
WriteNewSixInputEntry(ref currentNpad.JoyRightSixAxisSensor, ref newState); WriteNewSixInputEntry(ref currentNpad.JoyRightSixAxisSensor, ref newState);
} }
public void UpdateRumbleQueue(PlayerIndex index, Dictionary<byte, HidVibrationValue> dualVibrationValues) public void UpdateRumbleQueue(PlayerIndex index, Dictionary<byte, VibrationValue> dualVibrationValues)
{ {
if (RumbleQueues.TryGetValue(index, out ConcurrentQueue<(HidVibrationValue, HidVibrationValue)> currentQueue)) if (RumbleQueues.TryGetValue(index, out ConcurrentQueue<(VibrationValue, VibrationValue)> currentQueue))
{ {
if (!dualVibrationValues.TryGetValue(0, out HidVibrationValue leftVibrationValue)) if (!dualVibrationValues.TryGetValue(0, out VibrationValue leftVibrationValue))
{ {
leftVibrationValue = _neutralVibrationValue; leftVibrationValue = _neutralVibrationValue;
} }
if (!dualVibrationValues.TryGetValue(1, out HidVibrationValue rightVibrationValue)) if (!dualVibrationValues.TryGetValue(1, out VibrationValue rightVibrationValue))
{ {
rightVibrationValue = _neutralVibrationValue; rightVibrationValue = _neutralVibrationValue;
} }
if (!LastVibrationValues.TryGetValue(index, out (HidVibrationValue, HidVibrationValue) dualVibrationValue) || !leftVibrationValue.Equals(dualVibrationValue.Item1) || !rightVibrationValue.Equals(dualVibrationValue.Item2)) if (!LastVibrationValues.TryGetValue(index, out (VibrationValue, VibrationValue) dualVibrationValue) || !leftVibrationValue.Equals(dualVibrationValue.Item1) || !rightVibrationValue.Equals(dualVibrationValue.Item2))
{ {
currentQueue.Enqueue((leftVibrationValue, rightVibrationValue)); currentQueue.Enqueue((leftVibrationValue, rightVibrationValue));
@ -611,9 +611,9 @@ namespace Ryujinx.HLE.HOS.Services.Hid
} }
} }
public HidVibrationValue GetLastVibrationValue(PlayerIndex index, byte position) public VibrationValue GetLastVibrationValue(PlayerIndex index, byte position)
{ {
if (!LastVibrationValues.TryGetValue(index, out (HidVibrationValue, HidVibrationValue) dualVibrationValue)) if (!LastVibrationValues.TryGetValue(index, out (VibrationValue, VibrationValue) dualVibrationValue))
{ {
return _neutralVibrationValue; return _neutralVibrationValue;
} }
@ -621,11 +621,11 @@ namespace Ryujinx.HLE.HOS.Services.Hid
return (position == 0) ? dualVibrationValue.Item1 : dualVibrationValue.Item2; return (position == 0) ? dualVibrationValue.Item1 : dualVibrationValue.Item2;
} }
public ConcurrentQueue<(HidVibrationValue, HidVibrationValue)> GetRumbleQueue(PlayerIndex index) public ConcurrentQueue<(VibrationValue, VibrationValue)> GetRumbleQueue(PlayerIndex index)
{ {
if (!RumbleQueues.TryGetValue(index, out ConcurrentQueue<(HidVibrationValue, HidVibrationValue)> rumbleQueue)) if (!RumbleQueues.TryGetValue(index, out ConcurrentQueue<(VibrationValue, VibrationValue)> rumbleQueue))
{ {
rumbleQueue = new ConcurrentQueue<(HidVibrationValue, HidVibrationValue)>(); rumbleQueue = new ConcurrentQueue<(VibrationValue, VibrationValue)>();
_device.Hid.Npads.RumbleQueues[index] = rumbleQueue; _device.Hid.Npads.RumbleQueues[index] = rumbleQueue;
} }

View file

@ -35,5 +35,10 @@ namespace Ryujinx.HLE.HOS.Services.Hid.HidServer
PlayerIndex.Unknown => NpadIdType.Unknown, PlayerIndex.Unknown => NpadIdType.Unknown,
_ => throw new ArgumentOutOfRangeException(nameof(index)) _ => throw new ArgumentOutOfRangeException(nameof(index))
}; };
public static bool IsValidNpadIdType(NpadIdType npadIdType)
{
return npadIdType <= NpadIdType.Player8 || npadIdType == NpadIdType.Handheld || npadIdType == NpadIdType.Unknown;
}
} }
} }

View file

@ -1,8 +0,0 @@
namespace Ryujinx.HLE.HOS.Services.Hid
{
public enum HidNpadJoyAssignmentMode
{
Dual,
Single
}
}

View file

@ -1,6 +1,6 @@
namespace Ryujinx.HLE.HOS.Services.Hid namespace Ryujinx.HLE.HOS.Services.Hid
{ {
public enum HidNpadHandheldActivationMode public enum NpadHandheldActivationMode
{ {
Dual, Dual,
Single, Single,

View file

@ -1,6 +1,6 @@
namespace Ryujinx.HLE.HOS.Services.Hid namespace Ryujinx.HLE.HOS.Services.Hid
{ {
public enum HidNpadJoyDeviceType public enum NpadJoyDeviceType
{ {
Left, Left,
Right Right

View file

@ -1,6 +1,6 @@
namespace Ryujinx.HLE.HOS.Services.Hid namespace Ryujinx.HLE.HOS.Services.Hid
{ {
public struct HidAccelerometerParameters public struct AccelerometerParameters
{ {
public float X; public float X;
public float Y; public float Y;

View file

@ -1,6 +1,6 @@
namespace Ryujinx.HLE.HOS.Services.Hid namespace Ryujinx.HLE.HOS.Services.Hid
{ {
public enum HidGyroscopeZeroDriftMode public enum GyroscopeZeroDriftMode
{ {
Loose, Loose,
Standard, Standard,

View file

@ -1,6 +1,6 @@
namespace Ryujinx.HLE.HOS.Services.Hid namespace Ryujinx.HLE.HOS.Services.Hid
{ {
public struct HidSensorFusionParameters public struct SensorFusionParameters
{ {
public float RevisePower; public float RevisePower;
public float ReviseRange; public float ReviseRange;

View file

@ -1,8 +0,0 @@
namespace Ryujinx.HLE.HOS.Services.Hid
{
public struct HidVibrationDeviceValue
{
public HidVibrationDeviceType DeviceType;
public HidVibrationDevicePosition Position;
}
}

View file

@ -1,6 +1,6 @@
namespace Ryujinx.HLE.HOS.Services.Hid namespace Ryujinx.HLE.HOS.Services.Hid
{ {
public struct HidVibrationDeviceHandle public struct VibrationDeviceHandle
{ {
public byte DeviceType; public byte DeviceType;
public byte PlayerId; public byte PlayerId;

View file

@ -1,6 +1,6 @@
namespace Ryujinx.HLE.HOS.Services.Hid namespace Ryujinx.HLE.HOS.Services.Hid
{ {
public enum HidVibrationDevicePosition public enum VibrationDevicePosition
{ {
None, None,
Left, Left,

View file

@ -1,6 +1,6 @@
namespace Ryujinx.HLE.HOS.Services.Hid namespace Ryujinx.HLE.HOS.Services.Hid
{ {
public enum HidVibrationDeviceType public enum VibrationDeviceType
{ {
None, None,
LinearResonantActuator, LinearResonantActuator,

View file

@ -0,0 +1,8 @@
namespace Ryujinx.HLE.HOS.Services.Hid
{
public struct VibrationDeviceValue
{
public VibrationDeviceType DeviceType;
public VibrationDevicePosition Position;
}
}

View file

@ -1,9 +1,8 @@
using Ryujinx.HLE.HOS.Tamper; using System;
using System;
namespace Ryujinx.HLE.HOS.Services.Hid namespace Ryujinx.HLE.HOS.Services.Hid
{ {
public struct HidVibrationValue public struct VibrationValue
{ {
public float AmplitudeLow; public float AmplitudeLow;
public float FrequencyLow; public float FrequencyLow;
@ -12,7 +11,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
public override bool Equals(object obj) public override bool Equals(object obj)
{ {
return obj is HidVibrationValue value && return obj is VibrationValue value &&
AmplitudeLow == value.AmplitudeLow && AmplitudeLow == value.AmplitudeLow &&
AmplitudeHigh == value.AmplitudeHigh; AmplitudeHigh == value.AmplitudeHigh;
} }

View file

@ -5,6 +5,7 @@ using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Threading; using Ryujinx.HLE.HOS.Kernel.Threading;
using Ryujinx.HLE.HOS.Services.Hid.HidServer; using Ryujinx.HLE.HOS.Services.Hid.HidServer;
using Ryujinx.HLE.HOS.Services.Hid.Types; using Ryujinx.HLE.HOS.Services.Hid.Types;
using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Npad;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
@ -26,9 +27,8 @@ namespace Ryujinx.HLE.HOS.Services.Hid
private bool _isFirmwareUpdateAvailableForSixAxisSensor; private bool _isFirmwareUpdateAvailableForSixAxisSensor;
private bool _isSixAxisSensorUnalteredPassthroughEnabled; private bool _isSixAxisSensorUnalteredPassthroughEnabled;
private HidNpadJoyAssignmentMode _npadJoyAssignmentMode; private NpadHandheldActivationMode _npadHandheldActivationMode;
private HidNpadHandheldActivationMode _npadHandheldActivationMode; private GyroscopeZeroDriftMode _gyroscopeZeroDriftMode;
private HidGyroscopeZeroDriftMode _gyroscopeZeroDriftMode;
private long _npadCommunicationMode; private long _npadCommunicationMode;
private uint _accelerometerPlayMode; private uint _accelerometerPlayMode;
@ -37,22 +37,21 @@ namespace Ryujinx.HLE.HOS.Services.Hid
#pragma warning restore CS0649 #pragma warning restore CS0649
private float _sevenSixAxisSensorFusionStrength; private float _sevenSixAxisSensorFusionStrength;
private HidSensorFusionParameters _sensorFusionParams; private SensorFusionParameters _sensorFusionParams;
private HidAccelerometerParameters _accelerometerParams; private AccelerometerParameters _accelerometerParams;
public IHidServer(ServiceCtx context) : base(context.Device.System.HidServer) public IHidServer(ServiceCtx context) : base(context.Device.System.HidServer)
{ {
_xpadIdEvent = new KEvent(context.Device.System.KernelContext); _xpadIdEvent = new KEvent(context.Device.System.KernelContext);
_palmaOperationCompleteEvent = new KEvent(context.Device.System.KernelContext); _palmaOperationCompleteEvent = new KEvent(context.Device.System.KernelContext);
_npadJoyAssignmentMode = HidNpadJoyAssignmentMode.Dual; _npadHandheldActivationMode = NpadHandheldActivationMode.Dual;
_npadHandheldActivationMode = HidNpadHandheldActivationMode.Dual; _gyroscopeZeroDriftMode = GyroscopeZeroDriftMode.Standard;
_gyroscopeZeroDriftMode = HidGyroscopeZeroDriftMode.Standard;
_isFirmwareUpdateAvailableForSixAxisSensor = false; _isFirmwareUpdateAvailableForSixAxisSensor = false;
_sensorFusionParams = new HidSensorFusionParameters(); _sensorFusionParams = new SensorFusionParameters();
_accelerometerParams = new HidAccelerometerParameters(); _accelerometerParams = new AccelerometerParameters();
// TODO: signal event at right place // TODO: signal event at right place
_xpadIdEvent.ReadableEvent.Signal(); _xpadIdEvent.ReadableEvent.Signal();
@ -393,7 +392,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
int sixAxisSensorHandle = context.RequestData.ReadInt32(); int sixAxisSensorHandle = context.RequestData.ReadInt32();
context.RequestData.BaseStream.Position += 4; // Padding context.RequestData.BaseStream.Position += 4; // Padding
_sensorFusionParams = new HidSensorFusionParameters _sensorFusionParams = new SensorFusionParameters
{ {
RevisePower = context.RequestData.ReadInt32(), RevisePower = context.RequestData.ReadInt32(),
ReviseRange = context.RequestData.ReadInt32() ReviseRange = context.RequestData.ReadInt32()
@ -445,7 +444,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
int sixAxisSensorHandle = context.RequestData.ReadInt32(); int sixAxisSensorHandle = context.RequestData.ReadInt32();
context.RequestData.BaseStream.Position += 4; // Padding context.RequestData.BaseStream.Position += 4; // Padding
_accelerometerParams = new HidAccelerometerParameters _accelerometerParams = new AccelerometerParameters
{ {
X = context.RequestData.ReadInt32(), X = context.RequestData.ReadInt32(),
Y = context.RequestData.ReadInt32() Y = context.RequestData.ReadInt32()
@ -539,7 +538,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
public ResultCode SetGyroscopeZeroDriftMode(ServiceCtx context) public ResultCode SetGyroscopeZeroDriftMode(ServiceCtx context)
{ {
int sixAxisSensorHandle = context.RequestData.ReadInt32(); int sixAxisSensorHandle = context.RequestData.ReadInt32();
_gyroscopeZeroDriftMode = (HidGyroscopeZeroDriftMode)context.RequestData.ReadInt32(); _gyroscopeZeroDriftMode = (GyroscopeZeroDriftMode)context.RequestData.ReadInt32();
long appletResourceUserId = context.RequestData.ReadInt64(); long appletResourceUserId = context.RequestData.ReadInt64();
Logger.Stub?.PrintStub(LogClass.ServiceHid, new { appletResourceUserId, sixAxisSensorHandle, _gyroscopeZeroDriftMode }); Logger.Stub?.PrintStub(LogClass.ServiceHid, new { appletResourceUserId, sixAxisSensorHandle, _gyroscopeZeroDriftMode });
@ -570,7 +569,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
context.RequestData.BaseStream.Position += 4; // Padding context.RequestData.BaseStream.Position += 4; // Padding
long appletResourceUserId = context.RequestData.ReadInt64(); long appletResourceUserId = context.RequestData.ReadInt64();
_gyroscopeZeroDriftMode = HidGyroscopeZeroDriftMode.Standard; _gyroscopeZeroDriftMode = GyroscopeZeroDriftMode.Standard;
Logger.Stub?.PrintStub(LogClass.ServiceHid, new { appletResourceUserId, sixAxisSensorHandle, _gyroscopeZeroDriftMode }); Logger.Stub?.PrintStub(LogClass.ServiceHid, new { appletResourceUserId, sixAxisSensorHandle, _gyroscopeZeroDriftMode });
@ -909,54 +908,63 @@ namespace Ryujinx.HLE.HOS.Services.Hid
// SetNpadJoyAssignmentModeSingleByDefault(uint HidControllerId, nn::applet::AppletResourceUserId) // SetNpadJoyAssignmentModeSingleByDefault(uint HidControllerId, nn::applet::AppletResourceUserId)
public ResultCode SetNpadJoyAssignmentModeSingleByDefault(ServiceCtx context) public ResultCode SetNpadJoyAssignmentModeSingleByDefault(ServiceCtx context)
{ {
PlayerIndex hidControllerId = (PlayerIndex)context.RequestData.ReadInt32(); NpadIdType npadIdType = (NpadIdType)context.RequestData.ReadUInt32();
context.RequestData.BaseStream.Position += 4; // Padding
long appletResourceUserId = context.RequestData.ReadInt64(); long appletResourceUserId = context.RequestData.ReadInt64();
_npadJoyAssignmentMode = HidNpadJoyAssignmentMode.Single; if (HidUtils.IsValidNpadIdType(npadIdType))
{
Logger.Stub?.PrintStub(LogClass.ServiceHid, new { appletResourceUserId, hidControllerId, _npadJoyAssignmentMode }); context.Device.Hid.SharedMemory.Npads[(int)HidUtils.GetIndexFromNpadIdType(npadIdType)].InternalState.JoyAssignmentMode = NpadJoyAssignmentMode.Single;
}
return ResultCode.Success; return ResultCode.Success;
} }
[CommandHipc(123)] [CommandHipc(123)]
// SetNpadJoyAssignmentModeSingle(uint HidControllerId, nn::applet::AppletResourceUserId, long HidNpadJoyDeviceType) // SetNpadJoyAssignmentModeSingle(uint npadIdType, nn::applet::AppletResourceUserId, uint npadJoyDeviceType)
public ResultCode SetNpadJoyAssignmentModeSingle(ServiceCtx context) public ResultCode SetNpadJoyAssignmentModeSingle(ServiceCtx context)
{ {
PlayerIndex hidControllerId = (PlayerIndex)context.RequestData.ReadInt32(); NpadIdType npadIdType = (NpadIdType)context.RequestData.ReadUInt32();
context.RequestData.BaseStream.Position += 4; // Padding
long appletResourceUserId = context.RequestData.ReadInt64(); long appletResourceUserId = context.RequestData.ReadInt64();
HidNpadJoyDeviceType hidNpadJoyDeviceType = (HidNpadJoyDeviceType)context.RequestData.ReadInt64(); NpadJoyDeviceType npadJoyDeviceType = (NpadJoyDeviceType)context.RequestData.ReadUInt32();
_npadJoyAssignmentMode = HidNpadJoyAssignmentMode.Single; if (HidUtils.IsValidNpadIdType(npadIdType))
{
Logger.Stub?.PrintStub(LogClass.ServiceHid, new { appletResourceUserId, hidControllerId, hidNpadJoyDeviceType, _npadJoyAssignmentMode }); SetNpadJoyAssignmentModeSingleWithDestinationImpl(context, npadIdType, appletResourceUserId, npadJoyDeviceType, out _, out _);
}
return ResultCode.Success; return ResultCode.Success;
} }
[CommandHipc(124)] [CommandHipc(124)]
// SetNpadJoyAssignmentModeDual(uint HidControllerId, nn::applet::AppletResourceUserId) // SetNpadJoyAssignmentModeDual(uint npadIdType, nn::applet::AppletResourceUserId)
public ResultCode SetNpadJoyAssignmentModeDual(ServiceCtx context) public ResultCode SetNpadJoyAssignmentModeDual(ServiceCtx context)
{ {
PlayerIndex hidControllerId = HidUtils.GetIndexFromNpadIdType((NpadIdType)context.RequestData.ReadInt32()); NpadIdType npadIdType = (NpadIdType)context.RequestData.ReadUInt32();
context.RequestData.BaseStream.Position += 4; // Padding
long appletResourceUserId = context.RequestData.ReadInt64(); long appletResourceUserId = context.RequestData.ReadInt64();
_npadJoyAssignmentMode = HidNpadJoyAssignmentMode.Dual; if (HidUtils.IsValidNpadIdType(npadIdType))
{
Logger.Stub?.PrintStub(LogClass.ServiceHid, new { appletResourceUserId, hidControllerId, _npadJoyAssignmentMode }); context.Device.Hid.SharedMemory.Npads[(int)HidUtils.GetIndexFromNpadIdType(npadIdType)].InternalState.JoyAssignmentMode = NpadJoyAssignmentMode.Dual;
}
return ResultCode.Success; return ResultCode.Success;
} }
[CommandHipc(125)] [CommandHipc(125)]
// MergeSingleJoyAsDualJoy(uint SingleJoyId0, uint SingleJoyId1, nn::applet::AppletResourceUserId) // MergeSingleJoyAsDualJoy(uint npadIdType0, uint npadIdType1, nn::applet::AppletResourceUserId)
public ResultCode MergeSingleJoyAsDualJoy(ServiceCtx context) public ResultCode MergeSingleJoyAsDualJoy(ServiceCtx context)
{ {
long singleJoyId0 = context.RequestData.ReadInt32(); NpadIdType npadIdType0 = (NpadIdType)context.RequestData.ReadUInt32();
long singleJoyId1 = context.RequestData.ReadInt32(); NpadIdType npadIdType1 = (NpadIdType)context.RequestData.ReadUInt32();
long appletResourceUserId = context.RequestData.ReadInt64(); long appletResourceUserId = context.RequestData.ReadInt64();
Logger.Stub?.PrintStub(LogClass.ServiceHid, new { appletResourceUserId, singleJoyId0, singleJoyId1 }); if (HidUtils.IsValidNpadIdType(npadIdType0) && HidUtils.IsValidNpadIdType(npadIdType1))
{
Logger.Stub?.PrintStub(LogClass.ServiceHid, new { appletResourceUserId, npadIdType0, npadIdType1 });
}
return ResultCode.Success; return ResultCode.Success;
} }
@ -988,7 +996,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
public ResultCode SetNpadHandheldActivationMode(ServiceCtx context) public ResultCode SetNpadHandheldActivationMode(ServiceCtx context)
{ {
long appletResourceUserId = context.RequestData.ReadInt64(); long appletResourceUserId = context.RequestData.ReadInt64();
_npadHandheldActivationMode = (HidNpadHandheldActivationMode)context.RequestData.ReadInt64(); _npadHandheldActivationMode = (NpadHandheldActivationMode)context.RequestData.ReadInt64();
Logger.Stub?.PrintStub(LogClass.ServiceHid, new { appletResourceUserId, _npadHandheldActivationMode }); Logger.Stub?.PrintStub(LogClass.ServiceHid, new { appletResourceUserId, _npadHandheldActivationMode });
@ -1049,35 +1057,45 @@ namespace Ryujinx.HLE.HOS.Services.Hid
} }
[CommandHipc(133)] // 5.0.0+ [CommandHipc(133)] // 5.0.0+
// SetNpadJoyAssignmentModeSingleWithDestination(uint HidControllerId, long HidNpadJoyDeviceType, nn::applet::AppletResourceUserId) -> bool Unknown0, uint Unknown1 // SetNpadJoyAssignmentModeSingleWithDestination(uint npadIdType, uint npadJoyDeviceType, nn::applet::AppletResourceUserId) -> bool npadIdTypeIsSet, uint npadIdTypeSet
public ResultCode SetNpadJoyAssignmentModeSingleWithDestination(ServiceCtx context) public ResultCode SetNpadJoyAssignmentModeSingleWithDestination(ServiceCtx context)
{ {
PlayerIndex hidControllerId = (PlayerIndex)context.RequestData.ReadInt32(); NpadIdType npadIdType = (NpadIdType)context.RequestData.ReadInt32();
HidNpadJoyDeviceType hidNpadJoyDeviceType = (HidNpadJoyDeviceType)context.RequestData.ReadInt64(); NpadJoyDeviceType npadJoyDeviceType = (NpadJoyDeviceType)context.RequestData.ReadInt32();
context.RequestData.BaseStream.Position += 4; // Padding
long appletResourceUserId = context.RequestData.ReadInt64(); long appletResourceUserId = context.RequestData.ReadInt64();
_npadJoyAssignmentMode = HidNpadJoyAssignmentMode.Single; if (HidUtils.IsValidNpadIdType(npadIdType))
{
SetNpadJoyAssignmentModeSingleWithDestinationImpl(context, npadIdType, appletResourceUserId, npadJoyDeviceType, out NpadIdType npadIdTypeSet, out bool npadIdTypeIsSet);
context.ResponseData.Write(0); //Unknown0 if (npadIdTypeIsSet)
context.ResponseData.Write(0); //Unknown1 {
context.ResponseData.Write(npadIdTypeIsSet);
Logger.Stub?.PrintStub(LogClass.ServiceHid, new { context.ResponseData.Write((uint)npadIdTypeSet);
appletResourceUserId, }
hidControllerId, }
hidNpadJoyDeviceType,
_npadJoyAssignmentMode,
Unknown0 = 0,
Unknown1 = 0
});
return ResultCode.Success; return ResultCode.Success;
} }
private void SetNpadJoyAssignmentModeSingleWithDestinationImpl(ServiceCtx context, NpadIdType npadIdType, long appletResourceUserId, NpadJoyDeviceType npadJoyDeviceType, out NpadIdType npadIdTypeSet, out bool npadIdTypeIsSet)
{
npadIdTypeSet = default;
npadIdTypeIsSet = false;
context.Device.Hid.SharedMemory.Npads[(int)HidUtils.GetIndexFromNpadIdType(npadIdType)].InternalState.JoyAssignmentMode = NpadJoyAssignmentMode.Single;
// TODO: Service seems to use the npadJoyDeviceType to find the nearest other Npad available and merge them to dual.
// If one is found, it returns the npadIdType of the other Npad and a bool.
// If not, it returns nothing.
}
[CommandHipc(200)] [CommandHipc(200)]
// GetVibrationDeviceInfo(nn::hid::VibrationDeviceHandle) -> nn::hid::VibrationDeviceInfo // GetVibrationDeviceInfo(nn::hid::VibrationDeviceHandle) -> nn::hid::VibrationDeviceInfo
public ResultCode GetVibrationDeviceInfo(ServiceCtx context) public ResultCode GetVibrationDeviceInfo(ServiceCtx context)
{ {
HidVibrationDeviceHandle deviceHandle = context.RequestData.ReadStruct<HidVibrationDeviceHandle>(); VibrationDeviceHandle deviceHandle = context.RequestData.ReadStruct<VibrationDeviceHandle>();
NpadStyleIndex deviceType = (NpadStyleIndex)deviceHandle.DeviceType; NpadStyleIndex deviceType = (NpadStyleIndex)deviceHandle.DeviceType;
NpadIdType npadIdType = (NpadIdType)deviceHandle.PlayerId; NpadIdType npadIdType = (NpadIdType)deviceHandle.PlayerId;
@ -1093,28 +1111,28 @@ namespace Ryujinx.HLE.HOS.Services.Hid
return ResultCode.InvalidDeviceIndex; return ResultCode.InvalidDeviceIndex;
} }
HidVibrationDeviceType vibrationDeviceType = HidVibrationDeviceType.None; VibrationDeviceType vibrationDeviceType = VibrationDeviceType.None;
if (Enum.IsDefined<NpadStyleIndex>(deviceType)) if (Enum.IsDefined(deviceType))
{ {
vibrationDeviceType = HidVibrationDeviceType.LinearResonantActuator; vibrationDeviceType = VibrationDeviceType.LinearResonantActuator;
} }
else if ((uint)deviceType == 8) else if ((uint)deviceType == 8)
{ {
vibrationDeviceType = HidVibrationDeviceType.GcErm; vibrationDeviceType = VibrationDeviceType.GcErm;
} }
HidVibrationDevicePosition vibrationDevicePosition = HidVibrationDevicePosition.None; VibrationDevicePosition vibrationDevicePosition = VibrationDevicePosition.None;
if (vibrationDeviceType == HidVibrationDeviceType.LinearResonantActuator) if (vibrationDeviceType == VibrationDeviceType.LinearResonantActuator)
{ {
if (deviceHandle.Position == 0) if (deviceHandle.Position == 0)
{ {
vibrationDevicePosition = HidVibrationDevicePosition.Left; vibrationDevicePosition = VibrationDevicePosition.Left;
} }
else if (deviceHandle.Position == 1) else if (deviceHandle.Position == 1)
{ {
vibrationDevicePosition = HidVibrationDevicePosition.Right; vibrationDevicePosition = VibrationDevicePosition.Right;
} }
else else
{ {
@ -1122,7 +1140,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
} }
} }
HidVibrationDeviceValue deviceInfo = new HidVibrationDeviceValue VibrationDeviceValue deviceInfo = new VibrationDeviceValue
{ {
DeviceType = vibrationDeviceType, DeviceType = vibrationDeviceType,
Position = vibrationDevicePosition Position = vibrationDevicePosition
@ -1140,7 +1158,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
// SendVibrationValue(nn::hid::VibrationDeviceHandle, nn::hid::VibrationValue, nn::applet::AppletResourceUserId) // SendVibrationValue(nn::hid::VibrationDeviceHandle, nn::hid::VibrationValue, nn::applet::AppletResourceUserId)
public ResultCode SendVibrationValue(ServiceCtx context) public ResultCode SendVibrationValue(ServiceCtx context)
{ {
HidVibrationDeviceHandle deviceHandle = new HidVibrationDeviceHandle VibrationDeviceHandle deviceHandle = new VibrationDeviceHandle
{ {
DeviceType = context.RequestData.ReadByte(), DeviceType = context.RequestData.ReadByte(),
PlayerId = context.RequestData.ReadByte(), PlayerId = context.RequestData.ReadByte(),
@ -1148,7 +1166,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
Reserved = context.RequestData.ReadByte() Reserved = context.RequestData.ReadByte()
}; };
HidVibrationValue vibrationValue = new HidVibrationValue VibrationValue vibrationValue = new VibrationValue
{ {
AmplitudeLow = context.RequestData.ReadSingle(), AmplitudeLow = context.RequestData.ReadSingle(),
FrequencyLow = context.RequestData.ReadSingle(), FrequencyLow = context.RequestData.ReadSingle(),
@ -1158,7 +1176,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
long appletResourceUserId = context.RequestData.ReadInt64(); long appletResourceUserId = context.RequestData.ReadInt64();
Dictionary<byte, HidVibrationValue> dualVibrationValues = new Dictionary<byte, HidVibrationValue>(); Dictionary<byte, VibrationValue> dualVibrationValues = new Dictionary<byte, VibrationValue>();
dualVibrationValues[deviceHandle.Position] = vibrationValue; dualVibrationValues[deviceHandle.Position] = vibrationValue;
@ -1171,7 +1189,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
// GetActualVibrationValue(nn::hid::VibrationDeviceHandle, nn::applet::AppletResourceUserId) -> nn::hid::VibrationValue // GetActualVibrationValue(nn::hid::VibrationDeviceHandle, nn::applet::AppletResourceUserId) -> nn::hid::VibrationValue
public ResultCode GetActualVibrationValue(ServiceCtx context) public ResultCode GetActualVibrationValue(ServiceCtx context)
{ {
HidVibrationDeviceHandle deviceHandle = new HidVibrationDeviceHandle VibrationDeviceHandle deviceHandle = new VibrationDeviceHandle
{ {
DeviceType = context.RequestData.ReadByte(), DeviceType = context.RequestData.ReadByte(),
PlayerId = context.RequestData.ReadByte(), PlayerId = context.RequestData.ReadByte(),
@ -1181,7 +1199,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
long appletResourceUserId = context.RequestData.ReadInt64(); long appletResourceUserId = context.RequestData.ReadInt64();
HidVibrationValue vibrationValue = context.Device.Hid.Npads.GetLastVibrationValue((PlayerIndex)deviceHandle.PlayerId, deviceHandle.Position); VibrationValue vibrationValue = context.Device.Hid.Npads.GetLastVibrationValue((PlayerIndex)deviceHandle.PlayerId, deviceHandle.Position);
context.ResponseData.Write(vibrationValue.AmplitudeLow); context.ResponseData.Write(vibrationValue.AmplitudeLow);
context.ResponseData.Write(vibrationValue.FrequencyLow); context.ResponseData.Write(vibrationValue.FrequencyLow);
@ -1234,12 +1252,12 @@ namespace Ryujinx.HLE.HOS.Services.Hid
context.Memory.Read(context.Request.PtrBuff[1].Position, vibrationValueBuffer); context.Memory.Read(context.Request.PtrBuff[1].Position, vibrationValueBuffer);
Span<HidVibrationDeviceHandle> deviceHandles = MemoryMarshal.Cast<byte, HidVibrationDeviceHandle>(vibrationDeviceHandleBuffer); Span<VibrationDeviceHandle> deviceHandles = MemoryMarshal.Cast<byte, VibrationDeviceHandle>(vibrationDeviceHandleBuffer);
Span<HidVibrationValue> vibrationValues = MemoryMarshal.Cast<byte, HidVibrationValue>(vibrationValueBuffer); Span<VibrationValue> vibrationValues = MemoryMarshal.Cast<byte, VibrationValue>(vibrationValueBuffer);
if (!deviceHandles.IsEmpty && vibrationValues.Length == deviceHandles.Length) if (!deviceHandles.IsEmpty && vibrationValues.Length == deviceHandles.Length)
{ {
Dictionary<byte, HidVibrationValue> dualVibrationValues = new Dictionary<byte, HidVibrationValue>(); Dictionary<byte, VibrationValue> dualVibrationValues = new Dictionary<byte, VibrationValue>();
PlayerIndex currentIndex = (PlayerIndex)deviceHandles[0].PlayerId; PlayerIndex currentIndex = (PlayerIndex)deviceHandles[0].PlayerId;
for (int deviceCounter = 0; deviceCounter < deviceHandles.Length; deviceCounter++) for (int deviceCounter = 0; deviceCounter < deviceHandles.Length; deviceCounter++)
@ -1250,7 +1268,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
if (index != currentIndex || dualVibrationValues.Count == 2) if (index != currentIndex || dualVibrationValues.Count == 2)
{ {
context.Device.Hid.Npads.UpdateRumbleQueue(currentIndex, dualVibrationValues); context.Device.Hid.Npads.UpdateRumbleQueue(currentIndex, dualVibrationValues);
dualVibrationValues = new Dictionary<byte, HidVibrationValue>(); dualVibrationValues = new Dictionary<byte, VibrationValue>();
} }
dualVibrationValues[position] = vibrationValues[deviceCounter]; dualVibrationValues[position] = vibrationValues[deviceCounter];

View file

@ -543,14 +543,14 @@ namespace Ryujinx.Input.HLE
Dispose(true); Dispose(true);
} }
public void UpdateRumble(ConcurrentQueue<(HidVibrationValue, HidVibrationValue)> queue) public void UpdateRumble(ConcurrentQueue<(VibrationValue, VibrationValue)> queue)
{ {
if (queue.TryDequeue(out (HidVibrationValue, HidVibrationValue) dualVibrationValue)) if (queue.TryDequeue(out (VibrationValue, VibrationValue) dualVibrationValue))
{ {
if (_config is StandardControllerInputConfig controllerConfig && controllerConfig.Rumble.EnableRumble) if (_config is StandardControllerInputConfig controllerConfig && controllerConfig.Rumble.EnableRumble)
{ {
HidVibrationValue leftVibrationValue = dualVibrationValue.Item1; VibrationValue leftVibrationValue = dualVibrationValue.Item1;
HidVibrationValue rightVibrationValue = dualVibrationValue.Item2; VibrationValue rightVibrationValue = dualVibrationValue.Item2;
float low = Math.Min(1f, (float)((rightVibrationValue.AmplitudeLow * 0.85 + rightVibrationValue.AmplitudeHigh * 0.15) * controllerConfig.Rumble.StrongRumble)); float low = Math.Min(1f, (float)((rightVibrationValue.AmplitudeLow * 0.85 + rightVibrationValue.AmplitudeHigh * 0.15) * controllerConfig.Rumble.StrongRumble));
float high = Math.Min(1f, (float)((leftVibrationValue.AmplitudeLow * 0.15 + leftVibrationValue.AmplitudeHigh * 0.85) * controllerConfig.Rumble.WeakRumble)); float high = Math.Min(1f, (float)((leftVibrationValue.AmplitudeLow * 0.15 + leftVibrationValue.AmplitudeHigh * 0.85) * controllerConfig.Rumble.WeakRumble));