Brute force timer fix to the "stuck rumble motor" bug in ViGem virtual gamepad driver. This rumble autostop timer should be removed when a signed ViGem driver has a fix to this issue. Existing autostop timer is 2 secs, so this assumes that game keeps on updating a rumble values at least once in 2 secs. If rumble-0 event is lost or game doesn't send a new rumble value within 2 secs then rumble motor is automagically stopped (=assumed it is stuck). Usually games keep on sending rumble values as long an effect needs it, so this autostop timer works reasonable good in most games.

This commit is contained in:
mika-n 2019-04-06 15:04:21 +03:00
parent 21eb9770c7
commit 746587ebbd
3 changed files with 22 additions and 8 deletions

View File

@ -426,11 +426,11 @@ namespace DS4Windows
useDInputOnly[i] = false; useDInputOnly[i] = false;
x360controls[i] = new Xbox360Controller(vigemTestClient); x360controls[i] = new Xbox360Controller(vigemTestClient);
int devIndex = i; int devIndex = i;
/*x360controls[i].FeedbackReceived += (sender, args) => x360controls[i].FeedbackReceived += (sender, args) =>
{ {
SetDevRumble(device, args.LargeMotor, args.SmallMotor, devIndex); SetDevRumble(device, args.LargeMotor, args.SmallMotor, devIndex);
}; };
*/
x360controls[i].Connect(); x360controls[i].Connect();
LogDebug("X360 Controller #" + (i + 1) + " connected"); LogDebug("X360 Controller #" + (i + 1) + " connected");
} }
@ -683,11 +683,11 @@ namespace DS4Windows
useDInputOnly[Index] = false; useDInputOnly[Index] = false;
x360controls[Index] = new Xbox360Controller(vigemTestClient); x360controls[Index] = new Xbox360Controller(vigemTestClient);
int devIndex = Index; int devIndex = Index;
/*x360controls[Index].FeedbackReceived += (sender, args) => x360controls[Index].FeedbackReceived += (sender, args) =>
{ {
SetDevRumble(device, args.LargeMotor, args.SmallMotor, devIndex); SetDevRumble(device, args.LargeMotor, args.SmallMotor, devIndex);
}; };
*/
x360controls[Index].Connect(); x360controls[Index].Connect();
LogDebug("X360 Controller #" + (Index + 1) + " connected"); LogDebug("X360 Controller #" + (Index + 1) + " connected");
} }
@ -1060,11 +1060,11 @@ namespace DS4Windows
{ {
LogDebug("Plugging in X360 Controller #" + (ind + 1)); LogDebug("Plugging in X360 Controller #" + (ind + 1));
x360controls[ind] = new Xbox360Controller(vigemTestClient); x360controls[ind] = new Xbox360Controller(vigemTestClient);
/*x360controls[ind].FeedbackReceived += (eventsender, args) => x360controls[ind].FeedbackReceived += (eventsender, args) =>
{ {
SetDevRumble(device, args.LargeMotor, args.SmallMotor, ind); SetDevRumble(device, args.LargeMotor, args.SmallMotor, ind);
}; };
*/
x360controls[ind].Connect(); x360controls[ind].Connect();
useDInputOnly[ind] = false; useDInputOnly[ind] = false;
LogDebug("X360 Controller #" + (ind + 1) + " connected"); LogDebug("X360 Controller #" + (ind + 1) + " connected");

View File

@ -3064,11 +3064,11 @@ namespace DS4Windows
if (xinputStatus && xinputPlug) if (xinputStatus && xinputPlug)
{ {
control.x360controls[device] = new Nefarius.ViGEm.Client.Targets.Xbox360Controller(control.vigemTestClient); control.x360controls[device] = new Nefarius.ViGEm.Client.Targets.Xbox360Controller(control.vigemTestClient);
/*control.x360controls[device].FeedbackReceived += (eventsender, args) => control.x360controls[device].FeedbackReceived += (eventsender, args) =>
{ {
control.SetDevRumble(tempDev, args.LargeMotor, args.SmallMotor, device); control.SetDevRumble(tempDev, args.LargeMotor, args.SmallMotor, device);
}; };
*/
control.x360controls[device].Connect(); control.x360controls[device].Connect();
Global.useDInputOnly[device] = false; Global.useDInputOnly[device] = false;
AppLogger.LogToGui("X360 Controller #" + (device + 1) + " connected", false); AppLogger.LogToGui("X360 Controller #" + (device + 1) + " connected", false);

View File

@ -611,6 +611,8 @@ namespace DS4Windows
} }
} }
private readonly Stopwatch rumbleAutostopTimer = new Stopwatch(); // Autostop timer to stop rumble motors if those are stuck in a rumble state
private byte outputPendCount = 0; private byte outputPendCount = 0;
private readonly Stopwatch standbySw = new Stopwatch(); private readonly Stopwatch standbySw = new Stopwatch();
private unsafe void performDs4Output() private unsafe void performDs4Output()
@ -1210,6 +1212,13 @@ namespace DS4Windows
} }
} }
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
if (rumbleAutostopTimer.ElapsedMilliseconds >= 2000L)
setRumble(0, 0);
}
if (synchronous) if (synchronous)
{ {
if (output || haptime) if (output || haptime)
@ -1399,6 +1408,11 @@ namespace DS4Windows
testRumble.RumbleMotorStrengthRightLightFast = rightLightFastMotor; testRumble.RumbleMotorStrengthRightLightFast = rightLightFastMotor;
testRumble.RumbleMotorStrengthLeftHeavySlow = leftHeavySlowMotor; testRumble.RumbleMotorStrengthLeftHeavySlow = leftHeavySlowMotor;
testRumble.RumbleMotorsExplicitlyOff = rightLightFastMotor == 0 && leftHeavySlowMotor == 0; testRumble.RumbleMotorsExplicitlyOff = rightLightFastMotor == 0 && leftHeavySlowMotor == 0;
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()