User configurable (profile) max time in seconds for a rumble effect. The rumble watchdog timer used to be fixed 2 secs, but now it is possible to disable this watchdog timer (0 secs value) or set the max time in profile editor.

This commit is contained in:
mika-n 2020-01-05 22:11:44 +02:00
parent b74b37463c
commit 77e713e7b9
6 changed files with 86 additions and 12 deletions

View File

@ -980,6 +980,20 @@ namespace DS4Windows
return m_Config.rumble[index]; return m_Config.rumble[index];
} }
public static void setRumbleAutostopTime(int index, int value)
{
m_Config.rumbleAutostopTime[index] = value;
DS4Device tempDev = Program.rootHub.DS4Controllers[index];
if (tempDev != null && tempDev.isSynced())
tempDev.RumbleAutostopTime = value;
}
public static int getRumbleAutostopTime(int index)
{
return m_Config.rumbleAutostopTime[index];
}
public static double[] Rainbow => m_Config.rainbow; public static double[] Rainbow => m_Config.rainbow;
public static double getRainbow(int index) public static double getRainbow(int index)
{ {
@ -1949,6 +1963,7 @@ namespace DS4Windows
// Cache properties instead of performing a string comparison every frame // Cache properties instead of performing a string comparison every frame
public bool[] distanceProfiles = new bool[5] { false, false, false, false, false }; public bool[] distanceProfiles = new bool[5] { false, false, false, false, false };
public Byte[] rumble = new Byte[5] { 100, 100, 100, 100, 100 }; public Byte[] rumble = new Byte[5] { 100, 100, 100, 100, 100 };
public int[] rumbleAutostopTime = new int[5] { 0, 0, 0, 0, 0 }; // Value in milliseconds (0=autustop timer disabled)
public Byte[] touchSensitivity = new Byte[5] { 100, 100, 100, 100, 100 }; public Byte[] touchSensitivity = new Byte[5] { 100, 100, 100, 100, 100 };
public StickDeadZoneInfo[] lsModInfo = new StickDeadZoneInfo[5] public StickDeadZoneInfo[] lsModInfo = new StickDeadZoneInfo[5]
{ {
@ -2438,6 +2453,7 @@ namespace DS4Windows
xmlColor.InnerText = m_Leds[device].red.ToString() + "," + m_Leds[device].green.ToString() + "," + m_Leds[device].blue.ToString(); xmlColor.InnerText = m_Leds[device].red.ToString() + "," + m_Leds[device].green.ToString() + "," + m_Leds[device].blue.ToString();
Node.AppendChild(xmlColor); Node.AppendChild(xmlColor);
XmlNode xmlRumbleBoost = m_Xdoc.CreateNode(XmlNodeType.Element, "RumbleBoost", null); xmlRumbleBoost.InnerText = rumble[device].ToString(); Node.AppendChild(xmlRumbleBoost); XmlNode xmlRumbleBoost = m_Xdoc.CreateNode(XmlNodeType.Element, "RumbleBoost", null); xmlRumbleBoost.InnerText = rumble[device].ToString(); Node.AppendChild(xmlRumbleBoost);
XmlNode xmlRumbleAutostopTime = m_Xdoc.CreateNode(XmlNodeType.Element, "RumbleAutostopTime", null); xmlRumbleAutostopTime.InnerText = rumbleAutostopTime[device].ToString(); Node.AppendChild(xmlRumbleAutostopTime);
XmlNode xmlLedAsBatteryIndicator = m_Xdoc.CreateNode(XmlNodeType.Element, "ledAsBatteryIndicator", null); xmlLedAsBatteryIndicator.InnerText = ledAsBattery[device].ToString(); Node.AppendChild(xmlLedAsBatteryIndicator); XmlNode xmlLedAsBatteryIndicator = m_Xdoc.CreateNode(XmlNodeType.Element, "ledAsBatteryIndicator", null); xmlLedAsBatteryIndicator.InnerText = ledAsBattery[device].ToString(); Node.AppendChild(xmlLedAsBatteryIndicator);
XmlNode xmlLowBatteryFlash = m_Xdoc.CreateNode(XmlNodeType.Element, "FlashType", null); xmlLowBatteryFlash.InnerText = flashType[device].ToString(); Node.AppendChild(xmlLowBatteryFlash); XmlNode xmlLowBatteryFlash = m_Xdoc.CreateNode(XmlNodeType.Element, "FlashType", null); xmlLowBatteryFlash.InnerText = flashType[device].ToString(); Node.AppendChild(xmlLowBatteryFlash);
XmlNode xmlFlashBatterAt = m_Xdoc.CreateNode(XmlNodeType.Element, "flashBatteryAt", null); xmlFlashBatterAt.InnerText = flashAt[device].ToString(); Node.AppendChild(xmlFlashBatterAt); XmlNode xmlFlashBatterAt = m_Xdoc.CreateNode(XmlNodeType.Element, "flashBatteryAt", null); xmlFlashBatterAt.InnerText = flashAt[device].ToString(); Node.AppendChild(xmlFlashBatterAt);
@ -3084,6 +3100,9 @@ namespace DS4Windows
try { Item = m_Xdoc.SelectSingleNode("/" + rootname + "/RumbleBoost"); Byte.TryParse(Item.InnerText, out rumble[device]); } try { Item = m_Xdoc.SelectSingleNode("/" + rootname + "/RumbleBoost"); Byte.TryParse(Item.InnerText, out rumble[device]); }
catch { missingSetting = true; } catch { missingSetting = true; }
try { Item = m_Xdoc.SelectSingleNode("/" + rootname + "/RumbleAutostopTime"); Int32.TryParse(Item.InnerText, out rumbleAutostopTime[device]); }
catch { missingSetting = true; }
try { Item = m_Xdoc.SelectSingleNode("/" + rootname + "/ledAsBatteryIndicator"); Boolean.TryParse(Item.InnerText, out ledAsBattery[device]); } try { Item = m_Xdoc.SelectSingleNode("/" + rootname + "/ledAsBatteryIndicator"); Boolean.TryParse(Item.InnerText, out ledAsBattery[device]); }
catch { missingSetting = true; } catch { missingSetting = true; }
@ -4722,6 +4741,7 @@ namespace DS4Windows
ledAsBattery[device] = false; ledAsBattery[device] = false;
flashType[device] = 0; flashType[device] = 0;
rumble[device] = 100; rumble[device] = 100;
rumbleAutostopTime[device] = 0;
touchSensitivity[device] = 100; touchSensitivity[device] = 100;
l2ModInfo[device].deadZone = r2ModInfo[device].deadZone = 0; l2ModInfo[device].deadZone = r2ModInfo[device].deadZone = 0;
lsModInfo[device].deadZone = rsModInfo[device].deadZone = 10; lsModInfo[device].deadZone = rsModInfo[device].deadZone = 10;
@ -4909,7 +4929,8 @@ namespace DS4Windows
control.UnplugOutDev(device, tempDev); control.UnplugOutDev(device, tempDev);
} }
tempDev.setRumble(0, 0); tempDev.RumbleAutostopTime = rumbleAutostopTime[device];
tempDev.setRumble(0, 0);
}); });
Program.rootHub.touchPad[device]?.ResetTrackAccel(trackballFriction[device]); Program.rootHub.touchPad[device]?.ResetTrackAccel(trackballFriction[device]);

View File

@ -910,9 +910,11 @@
<StackPanel> <StackPanel>
<GroupBox Header="{lex:Loc Rumble}" MinHeight="50" Margin="4,4,4,0" Padding="0,4,0,4"> <GroupBox Header="{lex:Loc Rumble}" MinHeight="50" Margin="4,4,4,0" Padding="0,4,0,4">
<UniformGrid Rows="1" Columns="3"> <UniformGrid Rows="1" Columns="3">
<UniformGrid Columns="2"> <UniformGrid Columns="4" HorizontalAlignment="Left">
<xctk:IntegerUpDown x:Name="RumbleBoostIUD" d:IsHidden="True" MinWidth="60" Value="{Binding RumbleBoost}" Minimum="0" Maximum="200" Increment="10" /> <xctk:IntegerUpDown x:Name="RumbleBoostIUD" d:IsHidden="True" Value="{Binding RumbleBoost}" Minimum="0" Maximum="200" Increment="10" />
<Label Content="%" /> <Label Content="%" />
<xctk:IntegerUpDown x:Name="RumbleAutostopTimeIUD" d:IsHidden="True" Value="{Binding RumbleAutostopTime}" Minimum="0" Maximum="3600" Increment="1" ToolTip="{lex:Loc RumbleMaxSecsTip}"/>
<Label Content="{lex:Loc RumbleMaxSecs}" />
</UniformGrid> </UniformGrid>
<Button x:Name="heavyRumbleTestBtn" Content="Test Heavy" Margin="10,0,0,0" Click="HeavyRumbleTestBtn_Click" /> <Button x:Name="heavyRumbleTestBtn" Content="Test Heavy" Margin="10,0,0,0" Click="HeavyRumbleTestBtn_Click" />

View File

@ -342,6 +342,13 @@ namespace DS4WinWPF.DS4Forms.ViewModels
set => Global.RumbleBoost[device] = (byte)value; set => Global.RumbleBoost[device] = (byte)value;
} }
public int RumbleAutostopTime
{
// RumbleAutostopTime value is in milliseconds in XML config file, but GUI uses just seconds
get => Global.getRumbleAutostopTime(device) / 1000;
set => Global.setRumbleAutostopTime(device, value * 1000);
}
private bool heavyRumbleActive; private bool heavyRumbleActive;
public bool HeavyRumbleActive public bool HeavyRumbleActive
{ {

View File

@ -329,6 +329,24 @@ namespace DS4Windows
return currentHap.RumbleMotorStrengthLeftHeavySlow; return currentHap.RumbleMotorStrengthLeftHeavySlow;
} }
private int rumbleAutostopTime = 0;
public int RumbleAutostopTime
{
get { return rumbleAutostopTime; }
set
{
// Value in milliseconds
rumbleAutostopTime = value;
// If autostop timer is disabled (value 0) then stop existing autostop timer otherwise restart it
if (value <= 0)
rumbleAutostopTimer.Reset();
else
rumbleAutostopTimer.Restart();
}
}
public DS4Color LightBarColor public DS4Color LightBarColor
{ {
get { return currentHap.LightBarColor; } get { return currentHap.LightBarColor; }
@ -1251,7 +1269,7 @@ namespace DS4Windows
if (rumbleAutostopTimer.IsRunning) if (rumbleAutostopTimer.IsRunning)
{ {
// Workaround to a bug in ViGem driver. Force stop potentially stuck rumble motor on the next output report if there haven't been new rumble events within X seconds // Workaround to a bug in ViGem driver. Force stop potentially stuck rumble motor on the next output report if there haven't been new rumble events within X seconds
if (rumbleAutostopTimer.ElapsedMilliseconds >= 2000L) if (rumbleAutostopTimer.ElapsedMilliseconds >= rumbleAutostopTime)
setRumble(0, 0); setRumble(0, 0);
} }
@ -1445,10 +1463,14 @@ namespace DS4Windows
testRumble.RumbleMotorStrengthLeftHeavySlow = leftHeavySlowMotor; testRumble.RumbleMotorStrengthLeftHeavySlow = leftHeavySlowMotor;
testRumble.RumbleMotorsExplicitlyOff = rightLightFastMotor == 0 && leftHeavySlowMotor == 0; testRumble.RumbleMotorsExplicitlyOff = rightLightFastMotor == 0 && leftHeavySlowMotor == 0;
if (testRumble.RumbleMotorsExplicitlyOff) // If rumble autostop timer (msecs) is enabled for this device then restart autostop timer everytime rumble is modified (or stop the timer if rumble is set to zero)
rumbleAutostopTimer.Reset(); // Stop an autostop timer because ViGem driver sent properly a zero rumble notification if (rumbleAutostopTime > 0)
else {
rumbleAutostopTimer.Restart(); // Start an autostop timer to stop potentially stuck rumble motor because of lost rumble notification events from ViGem driver if (testRumble.RumbleMotorsExplicitlyOff)
rumbleAutostopTimer.Reset(); // Stop an autostop timer because ViGem driver sent properly a zero rumble notification
else
rumbleAutostopTimer.Restart(); // Start an autostop timer to stop potentially stuck rumble motor because of lost rumble notification events from ViGem driver
}
} }
private void MergeStates() private void MergeStates()

View File

@ -187,8 +187,7 @@ namespace DS4WinWPF.Translations {
} }
/// <summary> /// <summary>
/// Looks up a localized string similar to Clear /// Looks up a localized string similar to Clear.
///.
/// </summary> /// </summary>
public static string Clear { public static string Clear {
get { get {
@ -502,6 +501,24 @@ namespace DS4WinWPF.Translations {
} }
} }
/// <summary>
/// Looks up a localized string similar to sec.
/// </summary>
public static string RumbleMaxSecs {
get {
return ResourceManager.GetString("RumbleMaxSecs", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Auto stop rumble in secs (0=auto stop disabled).
/// </summary>
public static string RumbleMaxSecsTip {
get {
return ResourceManager.GetString("RumbleMaxSecsTip", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to Run At Startup. /// Looks up a localized string similar to Run At Startup.
/// </summary> /// </summary>
@ -584,8 +601,7 @@ namespace DS4WinWPF.Translations {
} }
/// <summary> /// <summary>
/// Looks up a localized string similar to Scroll /// Looks up a localized string similar to Scroll.
///.
/// </summary> /// </summary>
public static string TouchScroll { public static string TouchScroll {
get { get {

View File

@ -306,4 +306,10 @@
<data name="WarningsOnly" xml:space="preserve"> <data name="WarningsOnly" xml:space="preserve">
<value>Warnings only</value> <value>Warnings only</value>
</data> </data>
<data name="RumbleMaxSecs" xml:space="preserve">
<value>sec</value>
</data>
<data name="RumbleMaxSecsTip" xml:space="preserve">
<value>Auto stop rumble in secs (0=auto stop disabled)</value>
</data>
</root> </root>