mirror of
https://git.ryujinx.app/ryubing/ryujinx.git
synced 2026-06-27 14:49:05 +00:00
[HID] Restructure HD Rumble class for future controller support (#109)
- Attempted fixing the strength: so far it hasn't been successful. - Rumble should skip vibrations if they're not in-line with poll-rate: would like to come back to this. Queuing just does exactly what the hid buffer does, but our timer (poll rate) is not in sync with the rate the controller is reading at, which causes excess drops. - Refactored the class so that implementing support for HD rumble for other controllers (DS5, Steam Controller) is much easier in the future. Reviewed-on: https://git.ryujinx.app/projects/Ryubing/pulls/109
This commit is contained in:
@@ -9606,7 +9606,7 @@
|
|||||||
"ar_SA": "",
|
"ar_SA": "",
|
||||||
"de_DE": "",
|
"de_DE": "",
|
||||||
"el_GR": "",
|
"el_GR": "",
|
||||||
"en_US": "Sends more data to the controller for better rumble.\n\nCurrently only supports first-party Nintendo Switch controllers.\n\nLeave ON if you're using JoyCons or a Pro Controller.",
|
"en_US": "EXPERIMENTAL.\n\nSends more data to the controller for better rumble.\n\nCurrently only supports first-party Nintendo Switch controllers.\n\nLeave OFF if unsure.",
|
||||||
"es_ES": "",
|
"es_ES": "",
|
||||||
"fr_FR": "",
|
"fr_FR": "",
|
||||||
"he_IL": "",
|
"he_IL": "",
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
|||||||
private readonly bool[] _supportedPlayers;
|
private readonly bool[] _supportedPlayers;
|
||||||
private VibrationValue _neutralVibrationValue = new()
|
private VibrationValue _neutralVibrationValue = new()
|
||||||
{
|
{
|
||||||
AmplitudeLow = 0f,
|
AmplitudeLow = 0.01f,
|
||||||
FrequencyLow = 160f,
|
FrequencyLow = 160f,
|
||||||
AmplitudeHigh = 0f,
|
AmplitudeHigh = 0f,
|
||||||
FrequencyHigh = 320f,
|
FrequencyHigh = 320f,
|
||||||
|
|||||||
@@ -13,84 +13,98 @@ namespace Ryujinx.Input.SDL3
|
|||||||
{
|
{
|
||||||
private readonly SDL_hid_device* _hidHandle;
|
private readonly SDL_hid_device* _hidHandle;
|
||||||
|
|
||||||
|
private byte[] _buffer;
|
||||||
|
private static ushort _vendor;
|
||||||
|
private static ushort _product;
|
||||||
|
|
||||||
private int _globalCount;
|
private int _globalCount;
|
||||||
private ulong _lastWriteTicks;
|
private ulong _lastWriteTicks;
|
||||||
|
|
||||||
private NpadHdRumble(SDL_hid_device* hidHandle)
|
private NpadHdRumble(SDL_hid_device* hidHandle)
|
||||||
{
|
{
|
||||||
_hidHandle = hidHandle;
|
_hidHandle = hidHandle;
|
||||||
|
InitializeDevice();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static NpadHdRumble Create(SDL_Gamepad* gamepadHandle)
|
public static NpadHdRumble Create(SDL_Gamepad* gamepadHandle)
|
||||||
{
|
{
|
||||||
ushort vendor = SDL_GetGamepadVendor(gamepadHandle);
|
_vendor = SDL_GetGamepadVendor(gamepadHandle);
|
||||||
if (vendor != 0x057e)
|
if (!Enum.IsDefined(typeof(HDRumbleSupportedVendor), _vendor))
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
ushort product = SDL_GetGamepadProduct(gamepadHandle);
|
_product = SDL_GetGamepadProduct(gamepadHandle);
|
||||||
if (!Enum.IsDefined(typeof(HDRumbleSupported), product))
|
if (!Enum.IsDefined(typeof(HDRumbleSupportedProduct), _product))
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new NpadHdRumble(SDL_hid_open(vendor, product, 0));
|
int serialNumber = 0;
|
||||||
|
string? serial = SDL_GetGamepadSerial(gamepadHandle);
|
||||||
|
if (serial is not null)
|
||||||
|
{
|
||||||
|
int.TryParse(serial, out serialNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new NpadHdRumble(SDL_hid_open(_vendor, _product, serialNumber));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Some of the code was translated from https://github.com/MIZUSHIKI/JoyShockLibrary-plus-HDRumble
|
// Some of the code was translated from https://github.com/MIZUSHIKI/JoyShockLibrary-plus-HDRumble
|
||||||
private bool WriteHdRumble(
|
private bool WriteNintendoHdRumble(VibrationValue left, VibrationValue right)
|
||||||
int encLeftLowFreq, int encLeftLowAmp,
|
|
||||||
int encLeftHighFreq, int encLeftHighAmp,
|
|
||||||
int encRightLowFreq, int encRightLowAmp,
|
|
||||||
int encRightHighFreq, int encRightHighAmp)
|
|
||||||
{
|
{
|
||||||
byte[] buf = new byte[10];
|
int leftLowAmp = EncodeLowAmp(left.AmplitudeLow);
|
||||||
|
int leftLowFreq = EncodeLowFreq(left.FrequencyLow) + (leftLowAmp >> 8);
|
||||||
|
int leftHighFreq = EncodeHighFreq(left.FrequencyHigh);
|
||||||
|
int leftHighAmp = EncodeHighAmp(left.AmplitudeHigh) + (leftHighFreq >> 8);
|
||||||
|
|
||||||
buf[0] = 0x10;
|
int rightLowAmp = EncodeLowAmp(right.AmplitudeLow);
|
||||||
buf[1] = (byte)((++_globalCount) & 0xF);
|
int rightLowFreq = EncodeLowFreq(right.FrequencyLow) + (rightLowAmp >> 8);
|
||||||
|
int rightHighFreq = EncodeHighFreq(right.FrequencyHigh);
|
||||||
|
int rightHighAmp = EncodeHighAmp(right.AmplitudeHigh) + (rightHighFreq >> 8);
|
||||||
|
|
||||||
buf[2] = (byte)(encLeftHighFreq & 0xFF);
|
_buffer[0] = 0x10;
|
||||||
buf[3] = (byte)(encLeftHighAmp + ((encLeftHighFreq >> 8) & 0xFF));
|
_buffer[1] = (byte)((_globalCount++) & 0xF);
|
||||||
buf[4] = (byte)(encLeftLowFreq + ((encLeftLowAmp >> 8) & 0xFF));
|
|
||||||
buf[5] = (byte)(encLeftLowAmp & 0xFF);
|
|
||||||
|
|
||||||
buf[6] = (byte)(encRightHighFreq & 0xFF);
|
// Left LRA
|
||||||
buf[7] = (byte)(encRightHighAmp + ((encRightHighFreq >> 8) & 0xFF));
|
_buffer[2] = (byte)(leftLowFreq & 0xFF);
|
||||||
buf[8] = (byte)(encRightLowFreq + ((encRightLowAmp >> 8) & 0xFF));
|
_buffer[3] = (byte)(leftHighAmp & 0xFF);
|
||||||
buf[9] = (byte)(encRightLowAmp & 0xFF);
|
_buffer[4] = (byte)(leftHighFreq & 0xFF);
|
||||||
|
_buffer[5] = (byte)(leftLowAmp & 0xFF);
|
||||||
|
|
||||||
|
// Right LRA
|
||||||
|
_buffer[6] = (byte)(rightLowFreq & 0xFF);
|
||||||
|
_buffer[7] = (byte)(rightHighAmp & 0xFF);
|
||||||
|
_buffer[8] = (byte)(rightHighFreq & 0xFF);
|
||||||
|
_buffer[9] = (byte)(rightLowAmp & 0xFF);
|
||||||
|
|
||||||
if (_globalCount > 0xF)
|
if (_globalCount > 0xF)
|
||||||
{
|
{
|
||||||
_globalCount = 0x0;
|
_globalCount = 0x0;
|
||||||
}
|
}
|
||||||
|
|
||||||
fixed (byte* ptr = buf)
|
fixed (byte* ptr = _buffer)
|
||||||
{
|
{
|
||||||
if (SendHDRumble(ptr, (nuint)buf.Length) >= 0)
|
if (SendHdRumble(ptr, (nuint)_buffer.Length) >= 0)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!String.IsNullOrEmpty(SDL_GetError()))
|
|
||||||
{
|
|
||||||
Logger.Error?.PrintMsg(LogClass.Hid, SDL_GetError());
|
Logger.Error?.PrintMsg(LogClass.Hid, SDL_GetError());
|
||||||
SDL_ClearError();
|
SDL_ClearError();
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private static int EncodeLowFreq(float lowFreq)
|
private static int EncodeLowFreq(float lowFreq)
|
||||||
{
|
{
|
||||||
float lf = Math.Clamp(lowFreq, 40.875885f, 626.286133f);
|
return (int)Math.Clamp(32 * Math.Log2(lowFreq * 0.1f) - 0x40, 81.75177f, 1252.572266f);
|
||||||
return (int) Math.Round(32 * Math.Log2(lf * 0.1f) - 0x40);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int EncodeHighFreq(float highFreq)
|
private static int EncodeHighFreq(float highFreq)
|
||||||
{
|
{
|
||||||
float hf = Math.Clamp(highFreq, 81.75177f, 1252.572266f);
|
return (int)Math.Clamp(32 * Math.Log2(highFreq * 0.1f) - 0x60, 81.75177f, 1252.572266f);
|
||||||
return (int) Math.Round((32 * Math.Log2(hf * 0.1f) - 0x60) * 4);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int EncodeLowAmp(float rawAmp)
|
private static int EncodeLowAmp(float rawAmp)
|
||||||
@@ -98,23 +112,20 @@ namespace Ryujinx.Input.SDL3
|
|||||||
double encodedAmp = 0;
|
double encodedAmp = 0;
|
||||||
|
|
||||||
if (rawAmp is > 0 and < 0.012f)
|
if (rawAmp is > 0 and < 0.012f)
|
||||||
{
|
|
||||||
encodedAmp = 1;
|
encodedAmp = 1;
|
||||||
}
|
|
||||||
else if (rawAmp is >= 0.012f and < 0.112f)
|
|
||||||
{
|
|
||||||
encodedAmp = 4 * Math.Log2(rawAmp * 110f);
|
|
||||||
}
|
|
||||||
else if (rawAmp is >= 0.112f and < 0.225f)
|
|
||||||
{
|
|
||||||
encodedAmp = 16 * Math.Log2(rawAmp * 17f);
|
|
||||||
}
|
|
||||||
else if (rawAmp is >= 0.225f and <= 1f)
|
|
||||||
{
|
|
||||||
encodedAmp = 32 * Math.Log2(rawAmp * 8.7f);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (int)Math.Floor(encodedAmp / 2.0) + 64;
|
else if (rawAmp is >= 0.012f and < 0.112f)
|
||||||
|
encodedAmp = 4 * Math.Log2(rawAmp * 110f);
|
||||||
|
|
||||||
|
else if (rawAmp is >= 0.112f and < 0.225f)
|
||||||
|
encodedAmp = 16 * Math.Log2(rawAmp * 17f);
|
||||||
|
|
||||||
|
else if (rawAmp is >= 0.225f and <= 1f)
|
||||||
|
encodedAmp = 32 * Math.Log2(rawAmp * 8.7f);
|
||||||
|
|
||||||
|
encodedAmp = Math.Round((encodedAmp / 2.0) + 64.0);
|
||||||
|
encodedAmp = Math.Clamp(encodedAmp, 0.0, 100.2867);
|
||||||
|
return (int)Math.Round(encodedAmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int EncodeHighAmp(float rawAmp)
|
private static int EncodeHighAmp(float rawAmp)
|
||||||
@@ -122,82 +133,156 @@ namespace Ryujinx.Input.SDL3
|
|||||||
double encodedAmp = 0;
|
double encodedAmp = 0;
|
||||||
|
|
||||||
if (rawAmp is > 0 and < 0.012f)
|
if (rawAmp is > 0 and < 0.012f)
|
||||||
{
|
|
||||||
encodedAmp = 1;
|
encodedAmp = 1;
|
||||||
}
|
|
||||||
else if (rawAmp is >= 0.012f and < 0.112f)
|
|
||||||
{
|
|
||||||
encodedAmp = 4 * Math.Log2(rawAmp * 110f);
|
|
||||||
}
|
|
||||||
else if (rawAmp is >= 0.112f and < 0.225f)
|
|
||||||
{
|
|
||||||
encodedAmp = 16 * Math.Log2(rawAmp * 17f);
|
|
||||||
}
|
|
||||||
else if (rawAmp is >= 0.225f and <= 1f)
|
|
||||||
{
|
|
||||||
encodedAmp = 32 * Math.Log2(rawAmp * 8.7f);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (int) Math.Round(encodedAmp * 2);
|
else if (rawAmp is >= 0.012f and < 0.112f)
|
||||||
|
encodedAmp = 4 * Math.Log2(rawAmp * 110f);
|
||||||
|
|
||||||
|
else if (rawAmp is >= 0.112f and < 0.225f)
|
||||||
|
encodedAmp = 16 * Math.Log2(rawAmp * 17f);
|
||||||
|
|
||||||
|
else if (rawAmp is >= 0.225f and <= 1f)
|
||||||
|
encodedAmp = 32 * Math.Log2(rawAmp * 8.7f);
|
||||||
|
|
||||||
|
encodedAmp = Math.Round(encodedAmp / 2.0);
|
||||||
|
encodedAmp = Math.Clamp(encodedAmp, 0.0, 100.2867);
|
||||||
|
return (int)encodedAmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool HdRumble(VibrationValue left, VibrationValue right)
|
public bool HdRumble(VibrationValue left, VibrationValue right)
|
||||||
{
|
{
|
||||||
return WriteHdRumble(EncodeLowFreq(left.FrequencyLow),
|
if(_product is (ushort) HDRumbleSupportedProduct.ProController
|
||||||
EncodeLowAmp(left.AmplitudeLow),
|
or (ushort) HDRumbleSupportedProduct.JoyconLeft
|
||||||
EncodeHighFreq(left.FrequencyHigh),
|
or (ushort) HDRumbleSupportedProduct.JoyconRight
|
||||||
EncodeHighAmp(left.AmplitudeHigh),
|
or (ushort) HDRumbleSupportedProduct.JoyconPair
|
||||||
EncodeLowFreq(right.FrequencyLow),
|
or (ushort) HDRumbleSupportedProduct.JoyconGrip)
|
||||||
EncodeLowAmp(right.AmplitudeLow),
|
{
|
||||||
EncodeHighFreq(right.FrequencyHigh),
|
return WriteNintendoHdRumble(left, right);
|
||||||
EncodeHighAmp(right.AmplitudeHigh));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private int SendHDRumble(byte* data, nuint length)
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int SendHdRumble(byte* data, nuint length)
|
||||||
{
|
{
|
||||||
int result = 0;
|
int result = 0;
|
||||||
ulong currentTicks = SDL_GetTicks();
|
ulong currentTicks = SDL_GetTicks();
|
||||||
|
|
||||||
// Ditch rumble if we haven't hit the poll-rate yet.
|
// Ditch rumble if we haven't hit the poll-rate yet.
|
||||||
// TODO: figure out a better way to do this
|
if ((currentTicks - _lastWriteTicks) <= GetPollRate())
|
||||||
// While the polling check makes the rumble accurate, it also causes it to miss signals.
|
|
||||||
if ((currentTicks - _lastWriteTicks) < 8) // https://docs.handheldlegend.com/s/progcc-3/doc/lag-comparison-aAR1mV3JLX
|
|
||||||
{
|
{
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_LockJoysticks();
|
|
||||||
{
|
|
||||||
// Fun fact: Mario Kart 8 Deluxe sends rumble packets
|
|
||||||
// where the amplitude is zero, but the frequency isn't.
|
|
||||||
result = SDL_hid_write(_hidHandle, data, length);
|
result = SDL_hid_write(_hidHandle, data, length);
|
||||||
if (result >= 0)
|
if (result >= 0)
|
||||||
{
|
{
|
||||||
_lastWriteTicks = currentTicks;
|
_lastWriteTicks = currentTicks;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
SDL_UnlockJoysticks();
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void InitializeDevice()
|
||||||
|
{
|
||||||
|
if (_vendor is (ushort)HDRumbleSupportedVendor.Nintendo)
|
||||||
|
{
|
||||||
|
_buffer = new byte[10];
|
||||||
|
byte[] init = new byte[64];
|
||||||
|
|
||||||
|
// Pro Controller and Charge Grip
|
||||||
|
if (_product
|
||||||
|
is (ushort)HDRumbleSupportedProduct.ProController
|
||||||
|
or (ushort)HDRumbleSupportedProduct.JoyconGrip)
|
||||||
|
{
|
||||||
|
SDL_LockJoysticks();
|
||||||
|
fixed (byte* ptr = init)
|
||||||
|
{
|
||||||
|
init[0] = 0x80;
|
||||||
|
init[1] = 0x05; // Allow bluetooth timeout TODO: use 0x04 to force USB only (toggle?)
|
||||||
|
SDL_hid_write(_hidHandle, ptr, 64);
|
||||||
|
}
|
||||||
|
SDL_UnlockJoysticks();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Joycons
|
||||||
|
if (_product
|
||||||
|
is (ushort)HDRumbleSupportedProduct.JoyconLeft
|
||||||
|
or (ushort)HDRumbleSupportedProduct.JoyconRight
|
||||||
|
or (ushort)HDRumbleSupportedProduct.JoyconPair)
|
||||||
|
{
|
||||||
|
|
||||||
|
SDL_LockJoysticks();
|
||||||
|
fixed (byte* ptr = init)
|
||||||
|
{
|
||||||
|
// we could write data to the controller here (see above)
|
||||||
|
}
|
||||||
|
SDL_UnlockJoysticks();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ulong GetPollRate()
|
||||||
|
{
|
||||||
|
ulong pollRate = 0;
|
||||||
|
if (_vendor is (ushort)HDRumbleSupportedVendor.Nintendo)
|
||||||
|
{
|
||||||
|
// https://docs.handheldlegend.com/s/progcc-3/doc/lag-comparison-aAR1mV3JLX
|
||||||
|
pollRate = (ulong) 16.67;
|
||||||
|
if (_product is (ushort)HDRumbleSupportedProduct.ProController
|
||||||
|
&& SDL_hid_get_device_info(_hidHandle)->bus_type == SDL_hid_bus_type.SDL_HID_API_BUS_USB)
|
||||||
|
{
|
||||||
|
pollRate = (ulong) 8.33;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return pollRate;
|
||||||
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
SDL_hid_close(_hidHandle);
|
SDL_hid_close(_hidHandle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum HDRumbleSupported : ushort
|
public enum HDRumbleSupportedVendor : ushort
|
||||||
{
|
{
|
||||||
JoyConLeft = 0x2006,
|
Nintendo = 0x057e,
|
||||||
JoyConRight = 0x2007,
|
Valve = 0x28de,
|
||||||
|
Sony = 0x054c
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum HDRumbleSupportedProduct : ushort
|
||||||
|
{
|
||||||
|
// TODO: Currently, HD Rumble only supports the Pro Controller and JoyCons.
|
||||||
|
// We need to initialize and report to each device differently.
|
||||||
|
|
||||||
|
// Nintendo Switch: 0x057e
|
||||||
|
JoyconLeft = 0x2006,
|
||||||
|
JoyconRight = 0x2007,
|
||||||
JoyconPair = 0x2008,
|
JoyconPair = 0x2008,
|
||||||
ProController = 0x2009,
|
ProController = 0x2009,
|
||||||
JoyconGrip = 0x200e,
|
JoyconGrip = 0x200e,
|
||||||
|
|
||||||
|
// Nintendo Switch 2: 0x057e
|
||||||
Joycon2Right = 0x2066,
|
Joycon2Right = 0x2066,
|
||||||
Joycon2Left = 0x2067,
|
Joycon2Left = 0x2067,
|
||||||
Joycon2Pair = 0x2068,
|
Joycon2Pair = 0x2068,
|
||||||
Switch2ProController = 0x2069,
|
Switch2ProController = 0x2069,
|
||||||
GamecubeController = 0x2073
|
GamecubeController = 0x2073,
|
||||||
|
|
||||||
|
// Valve Steam Family: 0x28de
|
||||||
|
// https://github.com/libsdl-org/SDL/issues/9148
|
||||||
|
SteamDeck = 0x11ff,
|
||||||
|
SteamDeckVirtualDevice = 0x1205,
|
||||||
|
SteamController = 0x1106,
|
||||||
|
|
||||||
|
// PlayStation Dualsense: 0x054c
|
||||||
|
Dualsense = 0x0ce6
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -582,12 +582,12 @@ namespace Ryujinx.Input.HLE
|
|||||||
Logger.Debug?.Print(LogClass.Hid, $"Effect for {controllerConfig.PlayerIndex} " +
|
Logger.Debug?.Print(LogClass.Hid, $"Effect for {controllerConfig.PlayerIndex} " +
|
||||||
// Value=value/multiplier * multiplier (result)
|
// Value=value/multiplier * multiplier (result)
|
||||||
$"L.low.amp={leftVibrationValue.AmplitudeLow / controllerConfig.Rumble.WeakRumble} * {controllerConfig.Rumble.WeakRumble} ({leftVibrationValue.AmplitudeLow}), " +
|
$"L.low.amp={leftVibrationValue.AmplitudeLow / controllerConfig.Rumble.WeakRumble} * {controllerConfig.Rumble.WeakRumble} ({leftVibrationValue.AmplitudeLow}), " +
|
||||||
$"L.high.amp={leftVibrationValue.AmplitudeHigh / controllerConfig.Rumble.WeakRumble} * {controllerConfig.Rumble.WeakRumble} ({leftVibrationValue.AmplitudeHigh}), " +
|
$"L.high.amp={leftVibrationValue.AmplitudeHigh / controllerConfig.Rumble.StrongRumble} * {controllerConfig.Rumble.StrongRumble} ({leftVibrationValue.AmplitudeHigh}), " +
|
||||||
$"L.low.freq={leftVibrationValue.FrequencyLow / controllerConfig.Rumble.WeakRumble} * {controllerConfig.Rumble.WeakRumble} ({leftVibrationValue.FrequencyLow}), " +
|
$"L.low.freq={leftVibrationValue.FrequencyLow / controllerConfig.Rumble.WeakRumble} * {controllerConfig.Rumble.WeakRumble} ({leftVibrationValue.FrequencyLow}), " +
|
||||||
$"L.high.freq={leftVibrationValue.FrequencyHigh / controllerConfig.Rumble.WeakRumble} * {controllerConfig.Rumble.WeakRumble} ({leftVibrationValue.FrequencyHigh}), " +
|
$"L.high.freq={leftVibrationValue.FrequencyHigh / controllerConfig.Rumble.StrongRumble} * {controllerConfig.Rumble.StrongRumble} ({leftVibrationValue.FrequencyHigh}), " +
|
||||||
$"R.low.amp={rightVibrationValue.AmplitudeLow / controllerConfig.Rumble.StrongRumble} * {controllerConfig.Rumble.StrongRumble} ({rightVibrationValue.AmplitudeLow}), " +
|
$"R.low.amp={rightVibrationValue.AmplitudeLow / controllerConfig.Rumble.WeakRumble} * {controllerConfig.Rumble.WeakRumble} ({rightVibrationValue.AmplitudeLow}), " +
|
||||||
$"R.high.amp={rightVibrationValue.AmplitudeHigh / controllerConfig.Rumble.StrongRumble} * {controllerConfig.Rumble.StrongRumble} ({rightVibrationValue.AmplitudeHigh}), " +
|
$"R.high.amp={rightVibrationValue.AmplitudeHigh / controllerConfig.Rumble.StrongRumble} * {controllerConfig.Rumble.StrongRumble} ({rightVibrationValue.AmplitudeHigh}), " +
|
||||||
$"R.low.freq={rightVibrationValue.FrequencyLow / controllerConfig.Rumble.StrongRumble} * {controllerConfig.Rumble.StrongRumble} ({rightVibrationValue.FrequencyLow}), " +
|
$"R.low.freq={rightVibrationValue.FrequencyLow / controllerConfig.Rumble.WeakRumble} * {controllerConfig.Rumble.WeakRumble} ({rightVibrationValue.FrequencyLow}), " +
|
||||||
$"R.high.freq={rightVibrationValue.FrequencyHigh / controllerConfig.Rumble.StrongRumble} * {controllerConfig.Rumble.StrongRumble} ({rightVibrationValue.FrequencyHigh})");
|
$"R.high.freq={rightVibrationValue.FrequencyHigh / controllerConfig.Rumble.StrongRumble} * {controllerConfig.Rumble.StrongRumble} ({rightVibrationValue.FrequencyHigh})");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -140,7 +140,7 @@ namespace Ryujinx.Input
|
|||||||
StrongRumble = 1f,
|
StrongRumble = 1f,
|
||||||
WeakRumble = 1f,
|
WeakRumble = 1f,
|
||||||
EnableRumble = false,
|
EnableRumble = false,
|
||||||
UseHDRumble = true,
|
UseHDRumble = false
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -336,7 +336,7 @@ namespace Ryujinx.Ava.Systems.Configuration
|
|||||||
EnableRumble = false,
|
EnableRumble = false,
|
||||||
StrongRumble = 1f,
|
StrongRumble = 1f,
|
||||||
WeakRumble = 1f,
|
WeakRumble = 1f,
|
||||||
UseHDRumble = true
|
UseHDRumble = false
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user