From 746587ebbd720dc8d26ff76b48cd993ea23c0c4b Mon Sep 17 00:00:00 2001 From: mika-n Date: Sat, 6 Apr 2019 15:04:21 +0300 Subject: [PATCH] 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. --- DS4Windows/DS4Control/ControlService.cs | 12 ++++++------ DS4Windows/DS4Control/ScpUtil.cs | 4 ++-- DS4Windows/DS4Library/DS4Device.cs | 14 ++++++++++++++ 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/DS4Windows/DS4Control/ControlService.cs b/DS4Windows/DS4Control/ControlService.cs index b6aeeb1..fd5f350 100644 --- a/DS4Windows/DS4Control/ControlService.cs +++ b/DS4Windows/DS4Control/ControlService.cs @@ -426,11 +426,11 @@ namespace DS4Windows useDInputOnly[i] = false; x360controls[i] = new Xbox360Controller(vigemTestClient); int devIndex = i; - /*x360controls[i].FeedbackReceived += (sender, args) => + x360controls[i].FeedbackReceived += (sender, args) => { SetDevRumble(device, args.LargeMotor, args.SmallMotor, devIndex); }; - */ + x360controls[i].Connect(); LogDebug("X360 Controller #" + (i + 1) + " connected"); } @@ -683,11 +683,11 @@ namespace DS4Windows useDInputOnly[Index] = false; x360controls[Index] = new Xbox360Controller(vigemTestClient); int devIndex = Index; - /*x360controls[Index].FeedbackReceived += (sender, args) => + x360controls[Index].FeedbackReceived += (sender, args) => { SetDevRumble(device, args.LargeMotor, args.SmallMotor, devIndex); }; - */ + x360controls[Index].Connect(); LogDebug("X360 Controller #" + (Index + 1) + " connected"); } @@ -1060,11 +1060,11 @@ namespace DS4Windows { LogDebug("Plugging in X360 Controller #" + (ind + 1)); x360controls[ind] = new Xbox360Controller(vigemTestClient); - /*x360controls[ind].FeedbackReceived += (eventsender, args) => + x360controls[ind].FeedbackReceived += (eventsender, args) => { SetDevRumble(device, args.LargeMotor, args.SmallMotor, ind); }; - */ + x360controls[ind].Connect(); useDInputOnly[ind] = false; LogDebug("X360 Controller #" + (ind + 1) + " connected"); diff --git a/DS4Windows/DS4Control/ScpUtil.cs b/DS4Windows/DS4Control/ScpUtil.cs index 048eb76..0519925 100644 --- a/DS4Windows/DS4Control/ScpUtil.cs +++ b/DS4Windows/DS4Control/ScpUtil.cs @@ -3064,11 +3064,11 @@ namespace DS4Windows if (xinputStatus && xinputPlug) { 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.x360controls[device].Connect(); Global.useDInputOnly[device] = false; AppLogger.LogToGui("X360 Controller #" + (device + 1) + " connected", false); diff --git a/DS4Windows/DS4Library/DS4Device.cs b/DS4Windows/DS4Library/DS4Device.cs index e78bb6c..a3c0765 100644 --- a/DS4Windows/DS4Library/DS4Device.cs +++ b/DS4Windows/DS4Library/DS4Device.cs @@ -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 readonly Stopwatch standbySw = new Stopwatch(); 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 (output || haptime) @@ -1399,6 +1408,11 @@ namespace DS4Windows testRumble.RumbleMotorStrengthRightLightFast = rightLightFastMotor; testRumble.RumbleMotorStrengthLeftHeavySlow = leftHeavySlowMotor; 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()