Skip to content

Commit

Permalink
Additional methods. Renamed base class
Browse files Browse the repository at this point in the history
  • Loading branch information
Bob Helander committed Apr 22, 2021
1 parent d8022a2 commit cf6b58e
Show file tree
Hide file tree
Showing 10 changed files with 105 additions and 31 deletions.
4 changes: 4 additions & 0 deletions EDForceFeedback/App.config
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@
<assemblyIdentity name="System.ComponentModel.Annotations" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.2.1.0" newVersion="4.2.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-13.0.0.0" newVersion="13.0.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
10 changes: 8 additions & 2 deletions EDForceFeedback/EDForceFeedback.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,8 @@
<Reference Include="INIFileParser, Version=2.5.2.0, Culture=neutral, PublicKeyToken=79af7b307b65cf3c, processorArchitecture=MSIL">
<HintPath>..\packages\ini-parser.2.5.2\lib\net20\INIFileParser.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=12.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.12.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="SharpDX, Version=4.2.0.0, Culture=neutral, PublicKeyToken=b4dcf0f35e5521f1, processorArchitecture=MSIL">
<HintPath>..\packages\SharpDX.4.2.0\lib\net45\SharpDX.dll</HintPath>
Expand Down Expand Up @@ -125,6 +125,12 @@
<None Include="FFUtils\pid1_01.pdf">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<Content Include="Forces\Damper.ffe">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="Forces\CenterSpringXY.ffe">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<None Include="packages.config" />
<Content Include="settings.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
Expand Down
Binary file added EDForceFeedback/Forces/CenterSpringXY.ffe
Binary file not shown.
Binary file added EDForceFeedback/Forces/Damper.ffe
Binary file not shown.
2 changes: 1 addition & 1 deletion EDForceFeedback/packages.config
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<package id="Fody" version="6.2.0" targetFramework="net48" developmentDependency="true" />
<package id="ini-parser" version="2.5.2" targetFramework="net48" />
<package id="Microsoft.CSharp" version="4.7.0" targetFramework="net48" />
<package id="Newtonsoft.Json" version="12.0.3" targetFramework="net48" />
<package id="Newtonsoft.Json" version="13.0.1" targetFramework="net48" />
<package id="SharpDX" version="4.2.0" targetFramework="net48" />
<package id="SharpDX.DirectInput" version="4.2.0" targetFramework="net48" />
<package id="Somfic" version="1.1.7" targetFramework="net48" />
Expand Down
6 changes: 4 additions & 2 deletions EDForceFeedback/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": [
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<string, EffectInfo> knownEffects = new Dictionary<string, EffectInfo>();
private readonly Dictionary<string, List<EffectFile>> fileEffects = new Dictionary<string, List<EffectFile>>();

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();
Expand All @@ -33,6 +38,8 @@ public bool ForceFeedback2(string productGuid, string productName, bool AutoCent
var directInputDevices = new List<DeviceInstance>();

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));
Expand Down Expand Up @@ -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"))
{
Expand All @@ -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();
Expand All @@ -105,20 +113,23 @@ 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.
}

// 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;
}
Expand All @@ -139,46 +150,95 @@ private void PlayEffects(IEnumerable<Effect> effects)
PlayEffect(effect);
}

private void StopEffects(IEnumerable<Effect> effects)
/// <summary>
/// Stop any effects that were started from the PlayFileEffect() method.
/// </summary>
/// <param name="effects"></param>
public void StopEffects(IEnumerable<Effect> 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()
/// <summary>
/// Stop all effects. Reset to Default. Note: This reenables the center spring if autocenter is set.
/// </summary>
public void Reset()
{
joystick.SendForceFeedbackCommand(ForceFeedbackCommand.Reset);
}

public void PlayFileEffect(string name, int duration = 250)
/// <summary>
/// Stop all effects. Note: This will disable the autocenter effect. To reenable call Reset().
/// </summary>
public void StopAllEffects()
{
joystick.SendForceFeedbackCommand(ForceFeedbackCommand.StopAll);
}

/// <summary>
/// Set the actuators on/off
/// </summary>
public void SetActuators(bool on = true)
{
if (on)
joystick.SendForceFeedbackCommand(ForceFeedbackCommand.SetActuatorsOn);
else
joystick.SendForceFeedbackCommand(ForceFeedbackCommand.SetActuatorsOff);
}

/// <summary>
/// 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.
/// </summary>
/// <param name="name">Effect file name</param>
/// <param name="duration">Zero and below will play until stopped. Above zero will play for that many milliseconds. Default: 250.</param>
/// <returns>The effects being played as a List<Effect> or null if the effect file was not found.</returns>
public List<Effect> 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;
}
}
}
1 change: 1 addition & 0 deletions ForceFeedbackSharpDx/ForceFeedbackSharpDx.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<UserSecretsId>d3981932-571e-4587-9ab1-a84feafe7953</UserSecretsId>
</PropertyGroup>

<ItemGroup>
Expand Down
7 changes: 4 additions & 3 deletions Journals/Client.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion Journals/DeviceEvents.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ namespace Journals
{
public class DeviceEvents
{
public MicrosoftSidewinder Device { get; set; }
public ForceFeedbackController Device { get; set; }
public Dictionary<string, EventConfiguration> EventSettings { get; set; } = new Dictionary<string, EventConfiguration>();
}
}

0 comments on commit cf6b58e

Please sign in to comment.