Implement vibrations (#2468)
* First working vibration implementation * Fix Infinite Rumble in SDL2Mouse * Stop ignoring one vibValues every 2 * Remove RumbleInfinity as suggested * Reworked all the vibration handle / calculation * Revert HidVibrationDevicePosition changes * Add UI to enable and tune rumble * Remove some stub logs * Add PlayerIndex in rumble debug log * Fix all requested changes * Implements hid::GetVibrationDeviceInfo * Better implements HidVibrationValue.Equals/GetHashCode * Added requested changes from code review * Last fixes from review * Update configuration file version for rebase
This commit is contained in:
parent
46ffc81d90
commit
70f79e689b
18 changed files with 468 additions and 50 deletions
|
@ -1,10 +1,13 @@
|
|||
using Ryujinx.Common;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.HLE.HOS.Ipc;
|
||||
using Ryujinx.HLE.HOS.Kernel.Common;
|
||||
using Ryujinx.HLE.HOS.Kernel.Threading;
|
||||
using Ryujinx.HLE.HOS.Services.Hid.HidServer;
|
||||
using Ryujinx.HLE.HOS.Services.Hid.Types;
|
||||
using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Npad;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
|
@ -37,7 +40,6 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
|||
|
||||
private HidSensorFusionParameters _sensorFusionParams;
|
||||
private HidAccelerometerParameters _accelerometerParams;
|
||||
private HidVibrationValue _vibrationValue;
|
||||
|
||||
public IHidServer(ServiceCtx context) : base(context.Device.System.HidServer)
|
||||
{
|
||||
|
@ -52,7 +54,6 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
|||
|
||||
_sensorFusionParams = new HidSensorFusionParameters();
|
||||
_accelerometerParams = new HidAccelerometerParameters();
|
||||
_vibrationValue = new HidVibrationValue();
|
||||
|
||||
// TODO: signal event at right place
|
||||
_xpadIdEvent.ReadableEvent.Signal();
|
||||
|
@ -1025,29 +1026,78 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
|||
// GetVibrationDeviceInfo(nn::hid::VibrationDeviceHandle) -> nn::hid::VibrationDeviceInfo
|
||||
public ResultCode GetVibrationDeviceInfo(ServiceCtx context)
|
||||
{
|
||||
int vibrationDeviceHandle = context.RequestData.ReadInt32();
|
||||
HidVibrationDeviceHandle deviceHandle = context.RequestData.ReadStruct<HidVibrationDeviceHandle>();
|
||||
NpadStyleIndex deviceType = (NpadStyleIndex)deviceHandle.DeviceType;
|
||||
NpadIdType npadIdType = (NpadIdType)deviceHandle.PlayerId;
|
||||
|
||||
HidVibrationDeviceValue deviceInfo = new HidVibrationDeviceValue
|
||||
if (deviceType < NpadStyleIndex.System || deviceType >= NpadStyleIndex.FullKey)
|
||||
{
|
||||
DeviceType = HidVibrationDeviceType.None,
|
||||
Position = HidVibrationDevicePosition.None
|
||||
};
|
||||
if (npadIdType >= (NpadIdType.Player8 + 1) && npadIdType != NpadIdType.Handheld && npadIdType != NpadIdType.Unknown)
|
||||
{
|
||||
return ResultCode.InvalidNpadIdType;
|
||||
}
|
||||
|
||||
context.ResponseData.Write((int)deviceInfo.DeviceType);
|
||||
context.ResponseData.Write((int)deviceInfo.Position);
|
||||
if (deviceHandle.Position > 1)
|
||||
{
|
||||
return ResultCode.InvalidDeviceIndex;
|
||||
}
|
||||
|
||||
Logger.Stub?.PrintStub(LogClass.ServiceHid, new { vibrationDeviceHandle, deviceInfo.DeviceType, deviceInfo.Position });
|
||||
HidVibrationDeviceType vibrationDeviceType = HidVibrationDeviceType.None;
|
||||
|
||||
return ResultCode.Success;
|
||||
if (Enum.IsDefined(typeof(NpadStyleIndex), deviceType))
|
||||
{
|
||||
vibrationDeviceType = HidVibrationDeviceType.LinearResonantActuator;
|
||||
}
|
||||
else if ((uint)deviceType == 8)
|
||||
{
|
||||
vibrationDeviceType = HidVibrationDeviceType.GcErm;
|
||||
}
|
||||
|
||||
HidVibrationDevicePosition vibrationDevicePosition = HidVibrationDevicePosition.None;
|
||||
|
||||
if (vibrationDeviceType == HidVibrationDeviceType.LinearResonantActuator)
|
||||
{
|
||||
if (deviceHandle.Position == 0)
|
||||
{
|
||||
vibrationDevicePosition = HidVibrationDevicePosition.Left;
|
||||
}
|
||||
else if (deviceHandle.Position == 1)
|
||||
{
|
||||
vibrationDevicePosition = HidVibrationDevicePosition.Right;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(deviceHandle.Position));
|
||||
}
|
||||
}
|
||||
|
||||
HidVibrationDeviceValue deviceInfo = new HidVibrationDeviceValue
|
||||
{
|
||||
DeviceType = vibrationDeviceType,
|
||||
Position = vibrationDevicePosition
|
||||
};
|
||||
|
||||
context.ResponseData.WriteStruct(deviceInfo);
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
return ResultCode.InvalidNpadDeviceType;
|
||||
}
|
||||
|
||||
[CommandHipc(201)]
|
||||
// SendVibrationValue(nn::hid::VibrationDeviceHandle, nn::hid::VibrationValue, nn::applet::AppletResourceUserId)
|
||||
public ResultCode SendVibrationValue(ServiceCtx context)
|
||||
{
|
||||
int vibrationDeviceHandle = context.RequestData.ReadInt32();
|
||||
HidVibrationDeviceHandle deviceHandle = new HidVibrationDeviceHandle
|
||||
{
|
||||
DeviceType = context.RequestData.ReadByte(),
|
||||
PlayerId = context.RequestData.ReadByte(),
|
||||
Position = context.RequestData.ReadByte(),
|
||||
Reserved = context.RequestData.ReadByte()
|
||||
};
|
||||
|
||||
_vibrationValue = new HidVibrationValue
|
||||
HidVibrationValue vibrationValue = new HidVibrationValue
|
||||
{
|
||||
AmplitudeLow = context.RequestData.ReadSingle(),
|
||||
FrequencyLow = context.RequestData.ReadSingle(),
|
||||
|
@ -1057,14 +1107,11 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
|||
|
||||
long appletResourceUserId = context.RequestData.ReadInt64();
|
||||
|
||||
Logger.Debug?.PrintStub(LogClass.ServiceHid, new {
|
||||
appletResourceUserId,
|
||||
vibrationDeviceHandle,
|
||||
_vibrationValue.AmplitudeLow,
|
||||
_vibrationValue.FrequencyLow,
|
||||
_vibrationValue.AmplitudeHigh,
|
||||
_vibrationValue.FrequencyHigh
|
||||
});
|
||||
Dictionary<byte, HidVibrationValue> dualVibrationValues = new Dictionary<byte, HidVibrationValue>();
|
||||
|
||||
dualVibrationValues[deviceHandle.Position] = vibrationValue;
|
||||
|
||||
context.Device.Hid.Npads.UpdateRumbleQueue((PlayerIndex)deviceHandle.PlayerId, dualVibrationValues);
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
@ -1073,22 +1120,22 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
|||
// GetActualVibrationValue(nn::hid::VibrationDeviceHandle, nn::applet::AppletResourceUserId) -> nn::hid::VibrationValue
|
||||
public ResultCode GetActualVibrationValue(ServiceCtx context)
|
||||
{
|
||||
int vibrationDeviceHandle = context.RequestData.ReadInt32();
|
||||
HidVibrationDeviceHandle deviceHandle = new HidVibrationDeviceHandle
|
||||
{
|
||||
DeviceType = context.RequestData.ReadByte(),
|
||||
PlayerId = context.RequestData.ReadByte(),
|
||||
Position = context.RequestData.ReadByte(),
|
||||
Reserved = context.RequestData.ReadByte()
|
||||
};
|
||||
|
||||
long appletResourceUserId = context.RequestData.ReadInt64();
|
||||
|
||||
context.ResponseData.Write(_vibrationValue.AmplitudeLow);
|
||||
context.ResponseData.Write(_vibrationValue.FrequencyLow);
|
||||
context.ResponseData.Write(_vibrationValue.AmplitudeHigh);
|
||||
context.ResponseData.Write(_vibrationValue.FrequencyHigh);
|
||||
HidVibrationValue vibrationValue = context.Device.Hid.Npads.GetLastVibrationValue((PlayerIndex)deviceHandle.PlayerId, deviceHandle.Position);
|
||||
|
||||
Logger.Stub?.PrintStub(LogClass.ServiceHid, new {
|
||||
appletResourceUserId,
|
||||
vibrationDeviceHandle,
|
||||
_vibrationValue.AmplitudeLow,
|
||||
_vibrationValue.FrequencyLow,
|
||||
_vibrationValue.AmplitudeHigh,
|
||||
_vibrationValue.FrequencyHigh
|
||||
});
|
||||
context.ResponseData.Write(vibrationValue.AmplitudeLow);
|
||||
context.ResponseData.Write(vibrationValue.FrequencyLow);
|
||||
context.ResponseData.Write(vibrationValue.AmplitudeHigh);
|
||||
context.ResponseData.Write(vibrationValue.FrequencyHigh);
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
@ -1138,13 +1185,31 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
|||
|
||||
context.Memory.Read(context.Request.PtrBuff[1].Position, vibrationValueBuffer);
|
||||
|
||||
// TODO: Read all handles and values from buffer.
|
||||
Span<HidVibrationDeviceHandle> deviceHandles = MemoryMarshal.Cast<byte, HidVibrationDeviceHandle>(vibrationDeviceHandleBuffer);
|
||||
Span<HidVibrationValue> vibrationValues = MemoryMarshal.Cast<byte, HidVibrationValue>(vibrationValueBuffer);
|
||||
|
||||
Logger.Debug?.PrintStub(LogClass.ServiceHid, new {
|
||||
appletResourceUserId,
|
||||
VibrationDeviceHandleBufferLength = vibrationDeviceHandleBuffer.Length,
|
||||
VibrationValueBufferLength = vibrationValueBuffer.Length
|
||||
});
|
||||
if (!deviceHandles.IsEmpty && vibrationValues.Length == deviceHandles.Length)
|
||||
{
|
||||
Dictionary<byte, HidVibrationValue> dualVibrationValues = new Dictionary<byte, HidVibrationValue>();
|
||||
PlayerIndex currentIndex = (PlayerIndex)deviceHandles[0].PlayerId;
|
||||
|
||||
for (int deviceCounter = 0; deviceCounter < deviceHandles.Length; deviceCounter++)
|
||||
{
|
||||
PlayerIndex index = (PlayerIndex)deviceHandles[deviceCounter].PlayerId;
|
||||
byte position = deviceHandles[deviceCounter].Position;
|
||||
|
||||
if (index != currentIndex || dualVibrationValues.Count == 2)
|
||||
{
|
||||
context.Device.Hid.Npads.UpdateRumbleQueue(currentIndex, dualVibrationValues);
|
||||
dualVibrationValues = new Dictionary<byte, HidVibrationValue>();
|
||||
}
|
||||
|
||||
dualVibrationValues[position] = vibrationValues[deviceCounter];
|
||||
currentIndex = index;
|
||||
}
|
||||
|
||||
context.Device.Hid.Npads.UpdateRumbleQueue(currentIndex, dualVibrationValues);
|
||||
}
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue