SteamController: Add initial DS4 support (with Gyro, Accel, Trackpads and Haptics)

This commit is contained in:
Kamil Trzciński 2023-02-10 11:05:23 +01:00
parent 862d7afec5
commit 70237ad9d4
13 changed files with 739 additions and 33 deletions

View file

@ -9,6 +9,7 @@
## 0.6.x
- SteamController: Add initial `DS4` support (with Gyro, Accel, Trackpads and Haptics)
- PowerControl: Install custom resolutions (EDID) (experimental feature)
- SteamController: Add `X360: No Touchpads` profile
- All: Show `Missing RTSS` button to install RTSS

View file

@ -11,6 +11,7 @@ namespace SteamController
public Devices.SteamController Steam { get; private set; }
public Devices.Xbox360Controller X360 { get; private set; }
public Devices.DS4Controller DS4 { get; private set; }
public Devices.KeyboardController Keyboard { get; private set; }
public Devices.MouseController Mouse { get; private set; }
@ -25,11 +26,12 @@ namespace SteamController
public bool GameProcessRunning { get; set; }
public bool RTSSInForeground { get; set; }
public bool SteamUsesX360Controller { get; set; }
public bool SteamUsesDS4Controller { get; set; }
public bool SteamUsesSteamInput { get; set; }
public bool IsActive
{
get { return RTSSInForeground || GameProcessRunning || SteamUsesX360Controller || SteamUsesSteamInput; }
get { return RTSSInForeground || GameProcessRunning || SteamUsesX360Controller || SteamUsesDS4Controller || SteamUsesSteamInput; }
}
public override string ToString()
@ -37,6 +39,7 @@ namespace SteamController
string reason = "state";
if (GameProcessRunning) reason += " game";
if (SteamUsesX360Controller) reason += " steamX360";
if (SteamUsesDS4Controller) reason += " steamDS4";
if (SteamUsesSteamInput) reason += " steamInput";
if (RTSSInForeground) reason += " rtss";
return reason;
@ -78,6 +81,7 @@ namespace SteamController
{
Steam = new Devices.SteamController();
X360 = new Devices.Xbox360Controller();
DS4 = new Devices.DS4Controller();
Keyboard = new Devices.KeyboardController();
Mouse = new Devices.MouseController();
@ -92,6 +96,7 @@ namespace SteamController
using (Steam) { }
using (X360) { }
using (DS4) { }
using (Keyboard) { }
using (Mouse) { }
}
@ -99,6 +104,7 @@ namespace SteamController
public void Tick()
{
X360.Tick();
DS4.Tick();
foreach (var manager in Managers)
{
@ -111,6 +117,7 @@ namespace SteamController
{
Steam.BeforeUpdate();
X360.BeforeUpdate();
DS4.BeforeUpdate();
Keyboard.BeforeUpdate();
Mouse.BeforeUpdate();
@ -131,6 +138,7 @@ namespace SteamController
{
Steam.Update();
X360.Update();
DS4.Update();
Keyboard.Update();
Mouse.Update();
}

View file

@ -22,6 +22,7 @@ namespace SteamController
items.Add("[LM]");
items.Add(X360.Connected ? "[X360]" : X360.Valid ? "[no-X360]" : "[inv-X360]");
items.Add(DS4.Connected ? "[DS4]" : DS4.Valid ? "[no-DS4]" : "[inv-DS4]");
items.Add(KeyboardMouseValid ? "[KM]" : "[inv-KM]");
foreach (var button in Steam.AllButtons)

View file

@ -37,6 +37,7 @@ namespace SteamController
var nextReset = stopwatch.Elapsed.Add(UpdateResetInterval);
X360.Start();
DS4.Start();
while (threadRunning)
{
@ -58,6 +59,7 @@ namespace SteamController
}
X360.Stop();
DS4.Stop();
}
public void Stop()

View file

@ -30,7 +30,10 @@ namespace SteamController
new Profiles.Predefined.SteamProfile() { Name = "Steam", Visible = false },
new Profiles.Predefined.SteamWithShorcutsProfile() { Name = "Steam with Shortcuts", Visible = false },
new Profiles.Predefined.X360HapticProfile() { Name = "X360", EmulateTouchPads = true },
new Profiles.Predefined.X360HapticProfile() { Name = "X360: No Touchpads", EmulateTouchPads = false }
new Profiles.Predefined.X360HapticProfile() { Name = "X360: No Touchpads", EmulateTouchPads = false },
#if DEBUG
new Profiles.Predefined.DS4HapticProfile() { Name = "DS4" },
#endif
},
Managers = {
new Managers.ProcessManager(),
@ -274,8 +277,12 @@ namespace SteamController
Devices.Xbox360Controller.VendorID,
Devices.Xbox360Controller.ProductID
);
var blacklistedDS4Controller = Helpers.SteamConfiguration.IsControllerBlacklisted(
Devices.DS4Controller.VendorID,
Devices.DS4Controller.ProductID
);
if (blacklistedSteamController is null || blacklistedX360Controller is null)
if (blacklistedSteamController is null || blacklistedX360Controller is null || blacklistedDS4Controller is null)
{
// Appears that Steam is not installed
if (always)
@ -291,11 +298,12 @@ namespace SteamController
page.Caption = TitleWithVersion;
page.AllowCancel = true;
var useX360Controller = page.RadioButtons.Add("Use &X360 Controller with Steam (preferred)");
useX360Controller.Text += "\n- Will always use X360 controller.";
useX360Controller.Checked = Settings.Default.EnableSteamDetection == true &&
var useXInputController = page.RadioButtons.Add("Use &X360/DS4 Controller with Steam (preferred)");
useXInputController.Text += "\n- Will always use X360 or DS4 controller.";
useXInputController.Checked = Settings.Default.EnableSteamDetection == true &&
blacklistedSteamController == true &&
blacklistedX360Controller == false;
blacklistedX360Controller == false &&
blacklistedDS4Controller == false;
var useSteamInput = page.RadioButtons.Add("Use &Steam Input with Steam (requires configuration)");
useSteamInput.Text += "\n- Will try to use Steam controls.";
@ -303,13 +311,14 @@ namespace SteamController
useSteamInput.Text += "\n- Click Help for more information.";
useSteamInput.Checked = Settings.Default.EnableSteamDetection == true &&
blacklistedSteamController == false &&
blacklistedX360Controller == true;
blacklistedX360Controller == true &&
blacklistedDS4Controller == true;
var ignoreSteam = page.RadioButtons.Add("&Ignore Steam (only if you know why you need it)");
ignoreSteam.Text += "\n- Will revert all previously made changes.";
ignoreSteam.Checked = Settings.Default.EnableSteamDetection == false;
bool valid = ignoreSteam.Checked || useX360Controller.Checked || useSteamInput.Checked;
bool valid = ignoreSteam.Checked || useXInputController.Checked || useSteamInput.Checked;
// If everything is OK, on subsequent runs nothing to configure
if (valid && !always)
@ -352,16 +361,21 @@ namespace SteamController
var steamControllerUpdate = Helpers.SteamConfiguration.UpdateControllerBlacklist(
Devices.SteamController.VendorID,
Devices.SteamController.ProductID,
useX360Controller.Checked
useXInputController.Checked
);
var x360ControllerUpdate = Helpers.SteamConfiguration.UpdateControllerBlacklist(
Devices.Xbox360Controller.VendorID,
Devices.Xbox360Controller.ProductID,
useSteamInput.Checked
);
Settings.Default.EnableSteamDetection = useSteamInput.Checked || useX360Controller.Checked;
var ds4ControllerUpdate = Helpers.SteamConfiguration.UpdateControllerBlacklist(
Devices.DS4Controller.VendorID,
Devices.DS4Controller.ProductID,
useSteamInput.Checked
);
Settings.Default.EnableSteamDetection = useSteamInput.Checked || useXInputController.Checked;
if (steamControllerUpdate && x360ControllerUpdate)
if (steamControllerUpdate && x360ControllerUpdate && ds4ControllerUpdate)
{
notifyIcon.ShowBalloonTip(
3000, TitleWithVersion,
@ -399,7 +413,11 @@ namespace SteamController
{
Desktop = ProfilesSettings.DesktopPanelSettings.Default,
X360 = ProfilesSettings.X360BackPanelSettings.Default,
X360Haptic = ProfilesSettings.X360HapticSettings.Default,
X360Haptic = ProfilesSettings.HapticSettings.X360,
#if DEBUG
DS4 = ProfilesSettings.DS4BackPanelSettings.Default,
DS4Haptic = ProfilesSettings.HapticSettings.DS4,
#endif
Application = Settings.Default,
DEBUG = SettingsDebug.Default
}

View file

@ -0,0 +1,304 @@
using System.Diagnostics;
using Nefarius.ViGEm.Client;
using Nefarius.ViGEm.Client.Exceptions;
using Nefarius.ViGEm.Client.Targets;
using Nefarius.ViGEm.Client.Targets.DualShock4;
using Nefarius.ViGEm.Client.Targets.Xbox360;
using static CommonHelpers.Log;
namespace SteamController.Devices
{
public partial class DS4Controller : IDisposable
{
public readonly TimeSpan FeedbackTimeout = TimeSpan.FromMilliseconds(1000);
public const ushort VendorID = 0x054C;
public const ushort ProductID = 0x05C4;
private const int REPORT_SIZE = 63;
private const int TIMESTAMP_HZ = 800;
private const int TIMESTAMP_INCREMENT = 188;
private ViGEmClient? client;
private IDualShock4Controller? device;
private bool isConnected;
private byte[] reportBytes = new byte[REPORT_SIZE];
private bool submitReport;
private int submittedReports = 0;
private Stopwatch stopwatch = new Stopwatch();
public DS4Controller()
{
}
public void Dispose()
{
using (client) { }
}
public void Start()
{
}
public void Stop()
{
lock (this) { Fail(); }
}
internal bool Tick()
{
if (this.device is not null)
return true;
try
{
var client = new ViGEmClient();
var device = client.CreateDualShock4Controller();
device.AutoSubmitReport = false;
device.FeedbackReceived += DS4_FeedbackReceived;
this.device = device;
this.client = client;
return true;
}
catch (VigemBusNotFoundException)
{
// ViGem is not installed
return false;
}
}
private void Fail()
{
var client = this.client;
// unset current device
this.isConnected = false;
this.client = null;
this.device = null;
this.stopwatch.Stop();
try { using (client) { } }
catch (Exception) { }
}
private void PrepareReport()
{
var oldReportBytes = reportBytes;
reportBytes = new byte[63];
submitReport = false;
Counter.Set(reportBytes, (byte)((submittedReports << 2) & 0xFF));
BatteryLevel.Set(reportBytes, 255);
Timestamp.Set(reportBytes, (ushort)(stopwatch.ElapsedMilliseconds * TIMESTAMP_HZ * TIMESTAMP_INCREMENT / 1000));
DPadReleased.Set(reportBytes);
LeftThumbX.SetScaled(reportBytes, 0);
LeftThumbY.SetScaled(reportBytes, 0);
RightThumbX.SetScaled(reportBytes, 0);
RightThumbY.SetScaled(reportBytes, 0);
GyroX.Set(reportBytes, 0);
GyroY.Set(reportBytes, 0);
GyroZ.Set(reportBytes, 0);
AccelX.Set(reportBytes, 0);
AccelY.Set(reportBytes, 0);
AccelZ.Set(reportBytes, 0);
// Copy trackpad packets
reportBytes[32] = (byte)((reportBytes[32] + 1) & 0x3);
Array.Copy(oldReportBytes, 33, reportBytes, 33, 9);
Array.Copy(oldReportBytes, 33, reportBytes, 42, 9 * 2);
}
internal void BeforeUpdate()
{
device?.ResetReport();
if (!isConnected)
{
FeedbackLargeMotor = null;
FeedbackSmallMotor = null;
FeedbackReceived = null;
LightbarColor = null;
}
PrepareReport();
Connected = false;
}
private void SetConnected(bool wantsConnected)
{
if (wantsConnected == isConnected)
return;
if (wantsConnected)
{
try
{
device?.Connect();
stopwatch.Restart();
TraceLine("Connected DS4 Controller.");
}
catch (System.ComponentModel.Win32Exception e)
{
// This is expected exception (as sometimes device will fail to connect)
// ERROR_SUCCESS, which likely means COM did not succeed
if (e.NativeErrorCode == 0)
DebugException("DS4", "ConnectExpected", e);
else
TraceException("DS4", "ConnectExpected", e);
Fail();
return;
}
catch (Exception e)
{
TraceException("DS4", "Connect", e);
Fail();
return;
}
}
else
{
try
{
device?.Disconnect();
stopwatch.Stop();
TraceLine("Disconnected DS4 Controller.");
}
catch (VigemTargetNotPluggedInException)
{
// everything fine
}
catch (Exception e)
{
TraceException("DS4", "Disconnect", e);
Fail();
return;
}
}
isConnected = wantsConnected;
}
internal void Update()
{
if (device is not null && Connected != isConnected)
{
lock (this)
{
SetConnected(Connected);
}
}
if (isConnected && submitReport)
{
try
{
device?.SubmitRawReport(reportBytes);
submittedReports++;
}
catch (VigemInvalidTargetException)
{
// Device was lost
lock (this) { Fail(); }
}
catch (Exception e)
{
TraceException("DS4", "SubmitReport", e);
}
}
if (FeedbackReceived is not null && FeedbackReceived.Value.Add(FeedbackTimeout) < DateTime.Now)
{
FeedbackLargeMotor = null;
FeedbackSmallMotor = null;
FeedbackReceived = null;
}
}
public bool Valid
{
get { return device is not null; }
}
public bool Connected { get; set; }
public byte? FeedbackLargeMotor { get; private set; }
public byte? FeedbackSmallMotor { get; private set; }
public LightbarColor? LightbarColor { get; private set; }
public DateTime? FeedbackReceived { get; private set; }
public bool this[DualShock4Button button]
{
set
{
if (value)
button.Set(reportBytes, value);
submitReport = true;
}
}
public bool this[DualShock4DPadDirection button]
{
set
{
if (value)
button.Set(reportBytes);
submitReport = true;
}
}
public short this[DualShock4Axis axis]
{
set
{
axis.SetScaled(reportBytes, value);
submitReport = true;
}
}
public short this[DualShock4Slider slider]
{
set
{
slider.Set(reportBytes, value);
submitReport = true;
}
}
public short this[DualShock4Sensor sensor]
{
set
{
sensor.Set(reportBytes, value);
submitReport = true;
}
}
public Point? this[DualShock4Finger finger]
{
set
{
finger.Set(reportBytes, value);
submitReport = true;
}
}
public void Overwrite(DualShock4Button button, bool value, int minPressedTime = 0)
{
button.Set(reportBytes, value);
submitReport = true;
}
public void ResetFeedback()
{
FeedbackReceived = null;
}
private void DS4_FeedbackReceived(object sender, DualShock4FeedbackReceivedEventArgs e)
{
FeedbackLargeMotor = e.LargeMotor;
FeedbackSmallMotor = e.SmallMotor;
LightbarColor = e.LightbarColor;
FeedbackReceived = DateTime.Now;
}
}
}

View file

@ -0,0 +1,212 @@
using Nefarius.ViGEm.Client;
using Nefarius.ViGEm.Client.Exceptions;
using Nefarius.ViGEm.Client.Targets;
using Nefarius.ViGEm.Client.Targets.DualShock4;
using static CommonHelpers.Log;
namespace SteamController.Devices
{
public partial class DS4Controller
{
public struct DualShock4Axis
{
public int Offset { get; }
public bool Invert { get; }
public DualShock4Axis(int offset, bool invert)
{
Offset = offset;
Invert = invert;
}
internal void Set(byte[] report, byte value)
{
report[Offset] = value;
}
internal void SetScaled(byte[] report, short value)
{
var valuef = value / 256;
if (Invert)
valuef = -valuef;
Set(report, (byte)(valuef + sbyte.MinValue));
}
}
public struct DualShock4Button
{
public int Offset { get; }
public int Bit { get; }
public byte Mask { get => (byte)(1 << Bit); }
public DualShock4Button(int offset, int bit)
{
Offset = offset;
Bit = bit;
}
internal void Set(byte[] report, bool value)
{
report[Offset] = (byte)((report[Offset] & ~Mask) | (value ? Mask : 0));
}
}
public struct DualShock4DPadDirection
{
public int Offset { get; }
public int Value { get; }
public int Mask { get; }
public DualShock4DPadDirection(int offset, int value, int mask)
{
Offset = offset;
Value = value;
Mask = mask;
}
internal void Set(byte[] report)
{
report[Offset] = (byte)((report[Offset] & ~Mask) | Value);
}
}
public struct DualShock4Slider
{
public int Offset { get; }
public DualShock4Slider(int offset)
{
Offset = offset;
}
internal void Set(byte[] report, byte value)
{
report[Offset] = value;
}
internal void Set(byte[] report, short value)
{
int result = Math.Clamp(value, (short)0, short.MaxValue) * byte.MaxValue / short.MaxValue;
Set(report, (byte)result);
}
}
public struct DualShock4Sensor
{
public int Offset { get; }
public bool Invert { get; }
public DualShock4Sensor(int offset, bool invert)
{
Offset = offset;
Invert = invert;
}
internal void Set(byte[] report, short value)
{
if (Invert)
value = (short)Math.Clamp(-value, short.MinValue, short.MaxValue);
BitConverter.GetBytes(value).CopyTo(report, Offset);
}
internal void Set(byte[] report, ushort value)
{
BitConverter.GetBytes(value).CopyTo(report, Offset);
}
}
public struct DualShock4Finger
{
public const int MaxX = 1920;
public const int MaxY = 942;
public int Index { get; }
private int Offset { get => 34 + Index * 4; }
public DualShock4Finger(int index)
{
Index = index;
}
internal void Set(byte[] report, Point? data)
{
uint currentValue = BitConverter.ToUInt32(report, Offset);
// copy report ID
uint calculatedValue = (byte)(((currentValue & 0x7F) + 1) & 0x7F);
if (data.HasValue)
{
// store coordinates into report
int x = Math.Clamp(data.Value.X, 0, MaxX);
int y = Math.Clamp(data.Value.Y, 0, MaxY);
calculatedValue |= (uint)((x & 0x7FF) << 8);
calculatedValue |= (uint)((y & 0x7FF) << 20);
}
else
{
// copy existing coordinates
calculatedValue |= 0x80;
calculatedValue |= (uint)(currentValue & 0xFFFFFF00);
}
// compare position and key status
if ((currentValue & 0xFFFFFF80) == (calculatedValue & 0xFFFFFF80))
return;
// increment packet number
report[33] = (byte)(report[33] + 1);
BitConverter.GetBytes(calculatedValue).CopyTo(report, Offset);
}
}
public readonly static DualShock4Axis LeftThumbX = new DualShock4Axis(0, false);
public readonly static DualShock4Axis LeftThumbY = new DualShock4Axis(1, true);
public readonly static DualShock4Axis RightThumbX = new DualShock4Axis(2, false);
public readonly static DualShock4Axis RightThumbY = new DualShock4Axis(3, true);
public static DualShock4Slider LeftTrigger = new DualShock4Slider(7);
public static DualShock4Slider RightTrigger = new DualShock4Slider(8);
public static DualShock4Button ThumbRight = new DualShock4Button(5, 7);
public static DualShock4Button ThumbLeft = new DualShock4Button(5, 6);
public static DualShock4Button Options = new DualShock4Button(5, 5);
public static DualShock4Button Share = new DualShock4Button(5, 4);
public static DualShock4Button TriggerRight = new DualShock4Button(5, 3);
public static DualShock4Button TriggerLeft = new DualShock4Button(5, 2);
public static DualShock4Button ShoulderRight = new DualShock4Button(5, 1);
public static DualShock4Button ShoulderLeft = new DualShock4Button(5, 0);
public static DualShock4Button Triangle = new DualShock4Button(4, 7);
public static DualShock4Button Circle = new DualShock4Button(4, 6);
public static DualShock4Button Cross = new DualShock4Button(4, 5);
public static DualShock4Button Square = new DualShock4Button(4, 4);
public static DualShock4Button TPadClick = new DualShock4Button(6, 1);
public static DualShock4Button PS = new DualShock4Button(6, 0);
private static DualShock4Sensor Timestamp = new DualShock4Sensor(9, false);
private static DualShock4Slider BatteryLevel = new DualShock4Slider(11);
private static DualShock4Slider Counter = new DualShock4Slider(6);
public static DualShock4Sensor GyroX = new DualShock4Sensor(12, false);
public static DualShock4Sensor GyroY = new DualShock4Sensor(14, true);
public static DualShock4Sensor GyroZ = new DualShock4Sensor(16, false);
public static DualShock4Sensor AccelX = new DualShock4Sensor(18, false);
public static DualShock4Sensor AccelY = new DualShock4Sensor(20, true);
public static DualShock4Sensor AccelZ = new DualShock4Sensor(22, false);
public static DualShock4DPadDirection DPadReleased = new DualShock4DPadDirection(4, 8, 15);
public static DualShock4DPadDirection DPadNorthwest = new DualShock4DPadDirection(4, 7, 15);
public static DualShock4DPadDirection DPadWest = new DualShock4DPadDirection(4, 6, 15);
public static DualShock4DPadDirection DPadSouthwest = new DualShock4DPadDirection(4, 5, 15);
public static DualShock4DPadDirection DPadSouth = new DualShock4DPadDirection(4, 4, 15);
public static DualShock4DPadDirection DPadSoutheast = new DualShock4DPadDirection(4, 3, 15);
public static DualShock4DPadDirection DPadEast = new DualShock4DPadDirection(4, 2, 15);
public static DualShock4DPadDirection DPadNortheast = new DualShock4DPadDirection(4, 1, 15);
public static DualShock4DPadDirection DPadNorth = new DualShock4DPadDirection(4, 0, 15);
public static DualShock4Finger LeftFinger = new DualShock4Finger(0);
public static DualShock4Finger RightFinger = new DualShock4Finger(1);
}
}

View file

@ -30,6 +30,7 @@ namespace SteamController.Managers
{
context.State.SteamUsesSteamInput = false;
context.State.SteamUsesX360Controller = false;
context.State.SteamUsesDS4Controller = false;
lastState = null;
stateChanged = 0;
return;
@ -58,11 +59,17 @@ namespace SteamController.Managers
Devices.Xbox360Controller.VendorID,
Devices.Xbox360Controller.ProductID
) != true;
context.State.SteamUsesDS4Controller = Helpers.SteamConfiguration.IsControllerBlacklisted(
Devices.DS4Controller.VendorID,
Devices.DS4Controller.ProductID
) != true;
}
else
{
context.State.SteamUsesSteamInput = false;
context.State.SteamUsesX360Controller = false;
context.State.SteamUsesDS4Controller = false;
}
lastState = usesController;
@ -70,11 +77,12 @@ namespace SteamController.Managers
#if DEBUG
CommonHelpers.Log.TraceLine(
"SteamManager: uses={0}, isRunning={1}, usesSteamInput={2}, usesX360={3}",
"SteamManager: uses={0}, isRunning={1}, usesSteamInput={2}, usesX360={3}, usesDS4={4}",
usesController,
SteamConfiguration.IsRunning,
context.State.SteamUsesSteamInput,
context.State.SteamUsesX360Controller
context.State.SteamUsesX360Controller,
context.State.SteamUsesDS4Controller
);
#endif
}

View file

@ -0,0 +1,29 @@
using SteamController.ProfilesSettings;
using HapticPad = SteamController.Devices.SteamController.HapticPad;
namespace SteamController.Profiles.Predefined
{
public class DS4HapticProfile : DS4Profile
{
private ProfilesSettings.HapticSettings HapticSettings
{
get { return ProfilesSettings.HapticSettings.DS4; }
}
public override Status Run(Context context)
{
if (base.Run(context).IsDone)
return Status.Done;
if (HapticSettings.GetHapticIntensity(context.DS4.FeedbackLargeMotor, HapticSettings.LeftIntensity, out var leftIntensity))
context.Steam.SendHaptic(HapticPad.Right, HapticSettings.HapticStyle, leftIntensity);
if (HapticSettings.GetHapticIntensity(context.DS4.FeedbackSmallMotor, HapticSettings.RightIntensity, out var rightIntensity))
context.Steam.SendHaptic(HapticPad.Left, HapticSettings.HapticStyle, rightIntensity);
context.DS4.ResetFeedback();
return Status.Continue;
}
}
}

View file

@ -0,0 +1,106 @@
using Nefarius.ViGEm.Client.Targets.Xbox360;
using SteamController.Devices;
using SteamController.ProfilesSettings;
namespace SteamController.Profiles.Predefined
{
public class DS4Profile : Default.BackPanelShortcutsProfile
{
public override bool Selected(Context context)
{
return context.Enabled && context.DS4.Valid && context.KeyboardMouseValid && !context.State.SteamUsesSteamInput;
}
internal override ProfilesSettings.BackPanelSettings BackPanelSettings
{
get { return ProfilesSettings.DS4BackPanelSettings.Default; }
}
public override Status Run(Context context)
{
context.Steam.LizardButtons = false;
context.Steam.LizardMouse = false;
context.DS4.Connected = true;
// Controls
context.DS4.Overwrite(DS4Controller.PS, context.Steam.BtnSteam.Pressed(), 100);
context.DS4[DS4Controller.Share] = context.Steam.BtnMenu;
context.DS4[DS4Controller.Options] = context.Steam.BtnOptions;
if (base.Run(context).IsDone)
{
return Status.Done;
}
// DPad
if (context.Steam.BtnDpadUp && context.Steam.BtnDpadLeft)
context.DS4[DS4Controller.DPadNorthwest] = true;
else if (context.Steam.BtnDpadUp && context.Steam.BtnDpadRight)
context.DS4[DS4Controller.DPadNortheast] = true;
else if (context.Steam.BtnDpadDown && context.Steam.BtnDpadLeft)
context.DS4[DS4Controller.DPadSouthwest] = true;
else if (context.Steam.BtnDpadDown && context.Steam.BtnDpadRight)
context.DS4[DS4Controller.DPadSoutheast] = true;
else if (context.Steam.BtnDpadUp)
context.DS4[DS4Controller.DPadNorth] = true;
else if (context.Steam.BtnDpadDown)
context.DS4[DS4Controller.DPadSouth] = true;
else if (context.Steam.BtnDpadLeft)
context.DS4[DS4Controller.DPadWest] = true;
else if (context.Steam.BtnDpadRight)
context.DS4[DS4Controller.DPadEast] = true;
// Buttons
context.DS4[DS4Controller.Cross] = context.Steam.BtnA;
context.DS4[DS4Controller.Circle] = context.Steam.BtnB;
context.DS4[DS4Controller.Square] = context.Steam.BtnX;
context.DS4[DS4Controller.Triangle] = context.Steam.BtnY;
// Sticks
context.DS4[DS4Controller.LeftThumbX] = context.Steam.LeftThumbX;
context.DS4[DS4Controller.LeftThumbY] = context.Steam.LeftThumbY;
context.DS4[DS4Controller.RightThumbX] = context.Steam.RightThumbX;
context.DS4[DS4Controller.RightThumbY] = context.Steam.RightThumbY;
context.DS4[DS4Controller.ThumbLeft] = context.Steam.BtnLeftStickPress;
context.DS4[DS4Controller.ThumbRight] = context.Steam.BtnRightStickPress;
// Triggers
context.DS4[DS4Controller.LeftTrigger] = context.Steam.LeftTrigger;
context.DS4[DS4Controller.RightTrigger] = context.Steam.RightTrigger;
context.DS4[DS4Controller.TriggerLeft] = context.Steam.LeftTrigger > short.MaxValue * 3 / 4;
context.DS4[DS4Controller.TriggerRight] = context.Steam.RightTrigger > short.MaxValue * 3 / 4;
context.DS4[DS4Controller.ShoulderLeft] = context.Steam.BtnL1;
context.DS4[DS4Controller.ShoulderRight] = context.Steam.BtnR1;
// Accel & Gyro
context.DS4[DS4Controller.GyroX] = context.Steam.GyroPitch;
context.DS4[DS4Controller.GyroY] = context.Steam.GyroRoll;
context.DS4[DS4Controller.GyroZ] = context.Steam.GyroYaw;
context.DS4[DS4Controller.AccelX] = context.Steam.AccelX;
context.DS4[DS4Controller.AccelY] = context.Steam.AccelY;
context.DS4[DS4Controller.AccelZ] = context.Steam.AccelZ;
// Trackpad
context.DS4[DS4Controller.TPadClick] = context.Steam.BtnLPadPress || context.Steam.BtnRPadPress;
context.DS4[DS4Controller.LeftFinger] = GetTPadPoint(context.Steam.LPadX, context.Steam.LPadY);
context.DS4[DS4Controller.RightFinger] = GetTPadPoint(context.Steam.RPadX, context.Steam.RPadY);
return Status.Continue;
}
private Point? GetTPadPoint(SteamAxis x, SteamAxis y)
{
if (x || y)
{
return new Point(
(int)x.GetDeltaValue(0, 1920, DeltaValueMode.Absolute),
(int)y.GetDeltaValue(943 + 488, -488, DeltaValueMode.Absolute)
);
}
else
{
return null;
}
}
}
}

View file

@ -5,9 +5,9 @@ namespace SteamController.Profiles.Predefined
{
public class X360HapticProfile : X360Profile
{
private ProfilesSettings.X360HapticSettings HapticSettings
private ProfilesSettings.HapticSettings HapticSettings
{
get { return ProfilesSettings.X360HapticSettings.Default; }
get { return ProfilesSettings.HapticSettings.X360; }
}
public override Status Run(Context context)
@ -15,26 +15,15 @@ namespace SteamController.Profiles.Predefined
if (base.Run(context).IsDone)
return Status.Done;
if (GetHapticIntensity(context.X360.FeedbackLargeMotor, HapticSettings.LeftIntensity, out var leftIntensity))
if (HapticSettings.GetHapticIntensity(context.X360.FeedbackLargeMotor, HapticSettings.LeftIntensity, out var leftIntensity))
context.Steam.SendHaptic(HapticPad.Right, HapticSettings.HapticStyle, leftIntensity);
if (GetHapticIntensity(context.X360.FeedbackSmallMotor, HapticSettings.RightIntensity, out var rightIntensity))
if (HapticSettings.GetHapticIntensity(context.X360.FeedbackSmallMotor, HapticSettings.RightIntensity, out var rightIntensity))
context.Steam.SendHaptic(HapticPad.Left, HapticSettings.HapticStyle, rightIntensity);
context.X360.ResetFeedback();
return Status.Continue;
}
private bool GetHapticIntensity(byte? input, sbyte maxIntensity, out sbyte output)
{
output = default;
if (input is null || input.Value == 0)
return false;
int value = X360HapticSettings.MinIntensity + (maxIntensity - X360HapticSettings.MinIntensity) * input.Value / 255;
output = (sbyte)value;
return true;
}
}
}

View file

@ -0,0 +1,16 @@
using System.ComponentModel;
using System.Configuration;
namespace SteamController.ProfilesSettings
{
internal class DS4BackPanelSettings : BackPanelSettings
{
private const String MappingsDescription = @"Shortcuts are to be changed in future release.";
public static DS4BackPanelSettings Default { get; } = new DS4BackPanelSettings();
public DS4BackPanelSettings() : base("DS4BackPanelSettings")
{
}
}
}

View file

@ -4,17 +4,29 @@ using System.Configuration;
namespace SteamController.ProfilesSettings
{
[Category("Settings")]
internal sealed class X360HapticSettings : CommonHelpers.BaseSettings
internal sealed class HapticSettings : CommonHelpers.BaseSettings
{
public const sbyte MinIntensity = -2;
public const sbyte MaxIntensity = 10;
public static X360HapticSettings Default = new X360HapticSettings();
public static HapticSettings X360 = new HapticSettings("X360HapticSettings");
public static HapticSettings DS4 = new HapticSettings("DS4HapticSettings");
public X360HapticSettings() : base("X360HapticSettings")
public HapticSettings(string name) : base(name)
{
}
public static bool GetHapticIntensity(byte? input, sbyte maxIntensity, out sbyte output)
{
output = default;
if (input is null || input.Value == 0)
return false;
int value = MinIntensity + (maxIntensity - MinIntensity) * input.Value / 255;
output = (sbyte)value;
return true;
}
public Devices.SteamController.HapticStyle HapticStyle
{
get { return Get<Devices.SteamController.HapticStyle>("HapticStyle", Devices.SteamController.HapticStyle.Weak); }