diff --git a/EDForceFeedback/App.config b/EDForceFeedback/App.config
index 1c5ea9d..e420377 100644
--- a/EDForceFeedback/App.config
+++ b/EDForceFeedback/App.config
@@ -9,6 +9,10 @@
+
+
+
+
\ No newline at end of file
diff --git a/EDForceFeedback/EDForceFeedback.csproj b/EDForceFeedback/EDForceFeedback.csproj
index 4ee88c3..f68400b 100644
--- a/EDForceFeedback/EDForceFeedback.csproj
+++ b/EDForceFeedback/EDForceFeedback.csproj
@@ -61,8 +61,8 @@
..\packages\ini-parser.2.5.2\lib\net20\INIFileParser.dll
-
- ..\packages\Newtonsoft.Json.12.0.3\lib\net45\Newtonsoft.Json.dll
+
+ ..\packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll
..\packages\SharpDX.4.2.0\lib\net45\SharpDX.dll
@@ -125,6 +125,12 @@
Always
+
+ Always
+
+
+ Always
+
Always
diff --git a/EDForceFeedback/Forces/CenterSpringXY.ffe b/EDForceFeedback/Forces/CenterSpringXY.ffe
new file mode 100644
index 0000000..34ae9ce
Binary files /dev/null and b/EDForceFeedback/Forces/CenterSpringXY.ffe differ
diff --git a/EDForceFeedback/Forces/Damper.ffe b/EDForceFeedback/Forces/Damper.ffe
new file mode 100644
index 0000000..55fc7f0
Binary files /dev/null and b/EDForceFeedback/Forces/Damper.ffe differ
diff --git a/EDForceFeedback/packages.config b/EDForceFeedback/packages.config
index 10d63b8..c1da3c8 100644
--- a/EDForceFeedback/packages.config
+++ b/EDForceFeedback/packages.config
@@ -5,7 +5,7 @@
-
+
diff --git a/EDForceFeedback/settings.json b/EDForceFeedback/settings.json
index 32c20ac..bc946fe 100644
--- a/EDForceFeedback/settings.json
+++ b/EDForceFeedback/settings.json
@@ -12,8 +12,10 @@
"Devices": [
{
- "ProductGuid": "02dd045e-0000-0000-0000-504944564944",
- "ProductName": "Controller (Xbox One For Windows)",
+ "ProductGuid": "001b045e-0000-0000-0000-504944564944",
+ "ProductName": "SideWinder Force Feedback 2 Joystick",
+ "AutoCenter": true,
+ "ForceFeedbackGain": 10000,
"StatusEvents": [
{
diff --git a/ForceFeedbackSharpDx/MicrosoftSidewinder.cs b/ForceFeedbackSharpDx/ForceFeedbackController.cs
similarity index 61%
rename from ForceFeedbackSharpDx/MicrosoftSidewinder.cs
rename to ForceFeedbackSharpDx/ForceFeedbackController.cs
index a416256..78f8870 100644
--- a/ForceFeedbackSharpDx/MicrosoftSidewinder.cs
+++ b/ForceFeedbackSharpDx/ForceFeedbackController.cs
@@ -5,21 +5,26 @@
using System.Threading.Tasks;
using SharpDX.DirectInput;
using System.Linq;
+using SharpDX;
namespace ForceFeedbackSharpDx
{
- public class MicrosoftSidewinder
+ public class ForceFeedbackController
{
private const uint WINDOW_HANDLE_ERROR = 0x80070006;
- // Microsoft Force Feedback 2
- //private static Guid product = new Guid("001b045e-0000-0000-0000-504944564944");
-
private Joystick joystick = null;
private readonly Dictionary knownEffects = new Dictionary();
private readonly Dictionary> fileEffects = new Dictionary>();
- public bool ForceFeedback2(string productGuid, string productName, bool AutoCenter, int ForceFeedbackGain)
+ public bool Initialize(
+ string productGuid,
+ string productName,
+ string forceFilesFolder,
+ bool autoCenter,
+ int forceFeedbackGain,
+ int deadzone = 0,
+ int saturation = 10000)
{
// Initialize DirectInput
var directInput = new DirectInput();
@@ -33,6 +38,8 @@ public bool ForceFeedback2(string productGuid, string productName, bool AutoCent
var directInputDevices = new List();
directInputDevices.AddRange(directInput.GetDevices());
+
+ // Filtered
//directInputDevices.AddRange(directInput.GetDevices(DeviceType.Joystick, DeviceEnumerationFlags.AllDevices));
//directInputDevices.AddRange(directInput.GetDevices(DeviceType.Gamepad, DeviceEnumerationFlags.AllDevices));
//directInputDevices.AddRange(directInput.GetDevices(DeviceType.Driving, DeviceEnumerationFlags.AllDevices));
@@ -70,7 +77,7 @@ public bool ForceFeedback2(string productGuid, string productName, bool AutoCent
}
// Load all of the effect files
- var forcesFolder = new DirectoryInfo(@".\Forces");
+ var forcesFolder = new DirectoryInfo(forceFilesFolder);
foreach (var file in forcesFolder.GetFiles("*.ffe"))
{
@@ -87,9 +94,10 @@ public bool ForceFeedback2(string productGuid, string productName, bool AutoCent
try
{
+ // Exclusive is required to control the forces
joystick.SetCooperativeLevel(handle, CooperativeLevel.Exclusive | CooperativeLevel.Background);
}
- catch(SharpDX.SharpDXException ex ) when ((uint)ex.HResult == WINDOW_HANDLE_ERROR)
+ catch (SharpDX.SharpDXException ex) when ((uint)ex.HResult == WINDOW_HANDLE_ERROR)
{
Console.WriteLine();
Console.WriteLine();
@@ -105,10 +113,11 @@ public bool ForceFeedback2(string productGuid, string productName, bool AutoCent
try
{
- // Autocenter on
- joystick.Properties.AutoCenter = AutoCenter;
+ // Autocenter: For the MSFF2 joystick this value is a spring force that plays in the background.
+ // If all effects are stopped. The spring will stop too. Reset will turn it back on.
+ joystick.Properties.AutoCenter = autoCenter;
}
- catch (Exception _)
+ catch (SharpDXException)
{
// Some devices do not support this setting.
}
@@ -116,9 +125,11 @@ public bool ForceFeedback2(string productGuid, string productName, bool AutoCent
// Acquire the joystick
joystick.Acquire();
- //var test = joystick.Properties.ForceFeedbackGain;
+ SetActuators(true);
- joystick.Properties.ForceFeedbackGain = ForceFeedbackGain;
+ joystick.Properties.DeadZone = deadzone;
+ joystick.Properties.Saturation = saturation;
+ joystick.Properties.ForceFeedbackGain = forceFeedbackGain;
return true;
}
@@ -139,46 +150,95 @@ private void PlayEffects(IEnumerable effects)
PlayEffect(effect);
}
- private void StopEffects(IEnumerable effects)
+ ///
+ /// Stop any effects that were started from the PlayFileEffect() method.
+ ///
+ ///
+ public void StopEffects(IEnumerable effects)
{
foreach (var effect in effects)
- effect.Stop();
+ {
+ try { effect.Stop(); }
+ catch (SharpDXException) { }
+ }
foreach (var effect in effects)
- effect.Dispose();
+ effect?.Dispose();
- Reset();
+ //Reset(); // This will kill all effects
}
- private void Reset()
+ ///
+ /// Stop all effects. Reset to Default. Note: This reenables the center spring if autocenter is set.
+ ///
+ public void Reset()
{
joystick.SendForceFeedbackCommand(ForceFeedbackCommand.Reset);
}
- public void PlayFileEffect(string name, int duration = 250)
+ ///
+ /// Stop all effects. Note: This will disable the autocenter effect. To reenable call Reset().
+ ///
+ public void StopAllEffects()
+ {
+ joystick.SendForceFeedbackCommand(ForceFeedbackCommand.StopAll);
+ }
+
+ ///
+ /// Set the actuators on/off
+ ///
+ public void SetActuators(bool on = true)
+ {
+ if (on)
+ joystick.SendForceFeedbackCommand(ForceFeedbackCommand.SetActuatorsOn);
+ else
+ joystick.SendForceFeedbackCommand(ForceFeedbackCommand.SetActuatorsOff);
+ }
+
+ ///
+ /// Copy the effect file and begin playing it. If the duration is greater than zero the effect will play for that many milliseconds
+ /// and then be stopped.
+ ///
+ /// Effect file name
+ /// Zero and below will play until stopped. Above zero will play for that many milliseconds. Default: 250.
+ /// The effects being played as a List or null if the effect file was not found.
+ public List PlayFileEffect(string name, int duration = 250)
{
try
{
var fileEffect = fileEffects[name];
+ // Create a new List<> of effects
+ var forceEffects = fileEffect.ConvertAll(x => new Effect(joystick, x.Guid, x.Parameters));
+
_ = Task.Run(async () =>
{
- // Create a new list of effects
- var forceEffects = fileEffect.Select(x => new Effect(joystick, x.Guid, x.Parameters)).ToList();
PlayEffects(forceEffects);
- await Task.Delay(duration).ConfigureAwait(false);
- StopEffects(forceEffects);
+ if (duration > 0)
+ {
+ await Task.Delay(duration).ConfigureAwait(false);
+ StopEffects(forceEffects);
+ }
+ else
+ {
+ // Wait a moment, effects don't seem to play if we exit fast
+ await Task.Delay(100).ConfigureAwait(false);
+ }
}).ContinueWith(t =>
{
if (t.IsCanceled) Console.WriteLine($"Effect {name} cancelled");
else if (t.IsFaulted) Console.WriteLine($"Effect {name} Exception {t.Exception.InnerException?.Message}");
else Console.WriteLine($"Effect {name} complete");
});
+
+ return forceEffects;
}
catch (Exception ex)
{
Console.WriteLine($"Exception {ex.Message}");
}
+
+ return null;
}
}
}
diff --git a/ForceFeedbackSharpDx/ForceFeedbackSharpDx.csproj b/ForceFeedbackSharpDx/ForceFeedbackSharpDx.csproj
index 3a29620..cb35878 100644
--- a/ForceFeedbackSharpDx/ForceFeedbackSharpDx.csproj
+++ b/ForceFeedbackSharpDx/ForceFeedbackSharpDx.csproj
@@ -2,6 +2,7 @@
netstandard2.0
+ d3981932-571e-4587-9ab1-a84feafe7953
diff --git a/Journals/Client.cs b/Journals/Client.cs
index 84ce566..7fb508e 100644
--- a/Journals/Client.cs
+++ b/Journals/Client.cs
@@ -24,10 +24,11 @@ public void Initialize(Settings settings)
foreach (var device in settings.Devices)
{
- var ffDevice = new MicrosoftSidewinder();
- if (ffDevice.ForceFeedback2(
+ var ffDevice = new ForceFeedbackController();
+ if (ffDevice.Initialize(
device.ProductGuid,
device.ProductName,
+ @".\Forces",
device.AutoCenter,
device.ForceFeedbackGain) == false)
continue;
@@ -58,7 +59,7 @@ private void Events_AllEvent(object sender, dynamic e)
if (device.EventSettings.ContainsKey(key))
{
var eventConfig = device.EventSettings[key];
- device.Device?.PlayFileEffect(eventConfig.ForceFile, eventConfig.Duration);
+ var test = device.Device?.PlayFileEffect(eventConfig.ForceFile, eventConfig.Duration);
}
}
}
diff --git a/Journals/DeviceEvents.cs b/Journals/DeviceEvents.cs
index e22c357..34af6a5 100644
--- a/Journals/DeviceEvents.cs
+++ b/Journals/DeviceEvents.cs
@@ -7,7 +7,7 @@ namespace Journals
{
public class DeviceEvents
{
- public MicrosoftSidewinder Device { get; set; }
+ public ForceFeedbackController Device { get; set; }
public Dictionary EventSettings { get; set; } = new Dictionary();
}
}