SteamController: Add support for circular deadzone on left/right sticks

This is inspired by the changes https://github.com/ayufan/steam-deck-tools/pull/146,
but completely rewritten.

This removes `DeltaValue` methods, and `Deadzone` fixed values.
Adds a settings value for `Deadzone` per profile.
This commit is contained in:
Kamil Trzciński 2023-09-24 16:17:49 +02:00
parent 8abc01e8e3
commit c6b24bc573
12 changed files with 118 additions and 54 deletions

View file

@ -397,10 +397,10 @@ namespace SteamController
LargeButtons = true,
SelectedObject = new
{
Desktop = ProfilesSettings.DesktopPanelSettings.Default,
X360 = ProfilesSettings.X360BackPanelSettings.Default,
DesktopShortcuts = ProfilesSettings.DesktopPanelSettings.Default,
X360Shortcuts = ProfilesSettings.X360BackPanelSettings.Default,
X360Haptic = ProfilesSettings.HapticSettings.X360,
DS4 = ProfilesSettings.DS4BackPanelSettings.Default,
DS4Shortcuts = ProfilesSettings.DS4BackPanelSettings.Default,
DS4Haptic = ProfilesSettings.HapticSettings.DS4,
Application = Settings.Default,
#if DEBUG

View file

@ -271,9 +271,7 @@ namespace SteamController.Devices
public SteamButton? ActiveButton { get; internal set; }
public SteamButton? VirtualLeft { get; internal set; }
public SteamButton? VirtualRight { get; internal set; }
public short Deadzone { get; internal set; }
public short MinChange { get; internal set; }
public DeltaValueMode DeltaValueMode { get; internal set; } = DeltaValueMode.Absolute;
public SteamAxis[] DeadzoneAxis { get; internal set; } = new SteamAxis[0];
public short Value
{
@ -292,7 +290,7 @@ namespace SteamController.Devices
public static implicit operator bool(SteamAxis button) => button.Active;
public static implicit operator short(SteamAxis button)
{
return Math.Abs(button.Value) > button.Deadzone ? button.Value : (short)0;
return button.Value;
}
public bool Active
@ -300,39 +298,52 @@ namespace SteamController.Devices
get { return ActiveButton?.Value ?? true; }
}
public double DeltaValue
private bool CheckDeadzone(short deadzone)
{
get { return GetDeltaValue(-1, 1, DeltaValueMode); }
if (deadzone == 0)
return true;
int sum = Value * Value;
foreach (SteamAxis otherAxis in this.DeadzoneAxis)
sum += otherAxis.Value * otherAxis.Value;
return Math.Sqrt(sum) > deadzone;
}
public double GetDeltaValue(double min, double max, DeltaValueMode mode)
public short GetValue(short deadzone)
{
if (CheckDeadzone(deadzone))
return Value;
return 0;
}
public double GetDeltaValue(double range, DeltaValueMode mode, short deadzone)
{
return GetDeltaValue(-range, range, mode, deadzone);
}
public double GetDeltaValue(double min, double max, DeltaValueMode mode, short deadzone)
{
if (!CheckDeadzone(deadzone))
return 0.0;
int value = 0;
switch (mode)
{
case DeltaValueMode.Absolute:
if (Math.Abs(Value) < Deadzone)
return 0.0;
value = Value;
break;
case DeltaValueMode.AbsoluteTime:
if (Math.Abs(Value) < Deadzone)
return 0.0;
value = (int)(Value * (Controller?.DeltaTime ?? 0.0));
break;
case DeltaValueMode.Delta:
value = Value - LastValue;
if (Math.Abs(Value) < MinChange)
return 0.0;
break;
case DeltaValueMode.DeltaTime:
value = Value - LastValue;
if (Math.Abs(Value) < MinChange)
return 0.0;
value = (int)(value * (Controller?.DeltaTime ?? 0.0));
break;
}

View file

@ -40,10 +40,10 @@ namespace SteamController.Devices
public readonly SteamButton BtnVirtualLeftThumbLeft = new SteamButton();
public readonly SteamButton BtnVirtualLeftThumbRight = new SteamButton();
public readonly SteamAxis LPadX = new SteamAxis(0x10) { DeltaValueMode = Devices.DeltaValueMode.Delta };
public readonly SteamAxis LPadY = new SteamAxis(0x12) { DeltaValueMode = Devices.DeltaValueMode.Delta };
public readonly SteamAxis RPadX = new SteamAxis(0x14) { LizardMouse = true, DeltaValueMode = Devices.DeltaValueMode.Delta };
public readonly SteamAxis RPadY = new SteamAxis(0x16) { LizardMouse = true, DeltaValueMode = Devices.DeltaValueMode.Delta };
public readonly SteamAxis LPadX = new SteamAxis(0x10);
public readonly SteamAxis LPadY = new SteamAxis(0x12);
public readonly SteamAxis RPadX = new SteamAxis(0x14) { LizardMouse = true };
public readonly SteamAxis RPadY = new SteamAxis(0x16) { LizardMouse = true };
public readonly SteamAxis AccelX = new SteamAxis(0x18);
public readonly SteamAxis AccelY = new SteamAxis(0x1A);
public readonly SteamAxis AccelZ = new SteamAxis(0x1C);
@ -52,10 +52,10 @@ namespace SteamController.Devices
public readonly SteamAxis GyroYaw = new SteamAxis(0x22);
public readonly SteamAxis LeftTrigger = new SteamAxis(0x2C);
public readonly SteamAxis RightTrigger = new SteamAxis(0x2E);
public readonly SteamAxis LeftThumbX = new SteamAxis(0x30) { Deadzone = 5000, MinChange = 10, DeltaValueMode = Devices.DeltaValueMode.AbsoluteTime };
public readonly SteamAxis LeftThumbY = new SteamAxis(0x32) { Deadzone = 5000, MinChange = 10, DeltaValueMode = Devices.DeltaValueMode.AbsoluteTime };
public readonly SteamAxis RightThumbX = new SteamAxis(0x34) { Deadzone = 5000, MinChange = 10, DeltaValueMode = Devices.DeltaValueMode.AbsoluteTime };
public readonly SteamAxis RightThumbY = new SteamAxis(0x36) { Deadzone = 5000, MinChange = 10, DeltaValueMode = Devices.DeltaValueMode.AbsoluteTime };
public readonly SteamAxis LeftThumbX = new SteamAxis(0x30);
public readonly SteamAxis LeftThumbY = new SteamAxis(0x32);
public readonly SteamAxis RightThumbX = new SteamAxis(0x34);
public readonly SteamAxis RightThumbY = new SteamAxis(0x36);
public readonly SteamAxis LPadPressure = new SteamAxis(0x38);
public readonly SteamAxis RPadPressure = new SteamAxis(0x38);
@ -71,6 +71,12 @@ namespace SteamController.Devices
LeftThumbX.VirtualRight = BtnVirtualLeftThumbRight;
LeftThumbY.VirtualLeft = BtnVirtualLeftThumbDown;
LeftThumbY.VirtualRight = BtnVirtualLeftThumbUp;
// Include circular deadzone in calculation
LeftThumbX.DeadzoneAxis = new SteamAxis[] { LeftThumbY };
LeftThumbY.DeadzoneAxis = new SteamAxis[] { LeftThumbX };
RightThumbX.DeadzoneAxis = new SteamAxis[] { RightThumbY };
RightThumbY.DeadzoneAxis = new SteamAxis[] { RightThumbX };
}
}
}

View file

@ -122,11 +122,23 @@ namespace SteamController.Profiles.Default
{
if (c.Steam.LPadX)
{
c.Mouse.HorizontalScroll(c.Steam.LPadX.DeltaValue * Context.PadToWhellSensitivity);
c.Mouse.HorizontalScroll(
c.Steam.LPadX.GetDeltaValue(
Context.PadToWhellSensitivity,
Devices.DeltaValueMode.Delta,
10
)
);
}
if (c.Steam.LPadY)
{
c.Mouse.VerticalScroll(c.Steam.LPadY.DeltaValue * Context.PadToWhellSensitivity * (double)Settings.Default.ScrollDirection);
c.Mouse.HorizontalScroll(
c.Steam.LPadY.GetDeltaValue(
Context.PadToWhellSensitivity * (double)Settings.Default.ScrollDirection,
Devices.DeltaValueMode.Delta,
10
)
);
}
}
@ -135,8 +147,16 @@ namespace SteamController.Profiles.Default
if (c.Steam.RightThumbX || c.Steam.RightThumbY)
{
c.Mouse.MoveBy(
c.Steam.RightThumbX.DeltaValue * Context.JoystickToMouseSensitivity,
-c.Steam.RightThumbY.DeltaValue * Context.JoystickToMouseSensitivity
c.Steam.RightThumbX.GetDeltaValue(
Context.JoystickToMouseSensitivity,
Devices.DeltaValueMode.AbsoluteTime,
Settings.Default.DesktopJoystickDeadzone
),
-c.Steam.RightThumbY.GetDeltaValue(
Context.JoystickToMouseSensitivity,
Devices.DeltaValueMode.AbsoluteTime,
Settings.Default.DesktopJoystickDeadzone
)
);
}
}
@ -157,8 +177,8 @@ namespace SteamController.Profiles.Default
if (c.Steam.RPadX || c.Steam.RPadY)
{
c.Mouse.MoveBy(
c.Steam.RPadX.DeltaValue * Context.PadToMouseSensitivity,
-c.Steam.RPadY.DeltaValue * Context.PadToMouseSensitivity
c.Steam.RPadX.GetDeltaValue(Context.PadToMouseSensitivity, Devices.DeltaValueMode.Delta, 10),
-c.Steam.RPadY.GetDeltaValue(Context.PadToMouseSensitivity, Devices.DeltaValueMode.Delta, 10)
);
}
}

View file

@ -35,8 +35,9 @@ namespace SteamController.Profiles.Dynamic
public struct Axis
{
internal Devices.SteamAxis Target;
public static implicit operator short(Axis button) => button.Target;
public Axis(Devices.SteamAxis target) { Target = target; }
internal short Deadzone;
public static implicit operator short(Axis button) => button.Target.GetValue(button.Deadzone);
public Axis(Devices.SteamAxis target, short deadzone = 0) { Target = target; Deadzone = deadzone; }
}
public Button BtnL5 { get => new Button(Target.BtnL5); }
@ -85,10 +86,10 @@ namespace SteamController.Profiles.Dynamic
public Axis GyroRoll { get => new Axis(Target.GyroRoll); }
public Axis LeftTrigger { get => new Axis(Target.LeftTrigger); }
public Axis RightTrigger { get => new Axis(Target.RightTrigger); }
public Axis LeftThumbX { get => new Axis(Target.LeftThumbX); }
public Axis LeftThumbY { get => new Axis(Target.LeftThumbY); }
public Axis RightThumbX { get => new Axis(Target.RightThumbX); }
public Axis RightThumbY { get => new Axis(Target.RightThumbY); }
public Axis LeftThumbX { get => new Axis(Target.LeftThumbX, Settings.Default.JoystickDeadzone); }
public Axis LeftThumbY { get => new Axis(Target.LeftThumbY, Settings.Default.JoystickDeadzone); }
public Axis RightThumbX { get => new Axis(Target.RightThumbX, Settings.Default.JoystickDeadzone); }
public Axis RightThumbY { get => new Axis(Target.RightThumbY, Settings.Default.JoystickDeadzone); }
public Axis LPadPressure { get => new Axis(Target.LPadPressure); }
public Axis RPadPressure { get => new Axis(Target.RPadPressure); }
}

View file

@ -80,10 +80,10 @@ namespace SteamController.Profiles.Predefined
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.LeftThumbX] = context.Steam.LeftThumbX.GetValue(Settings.Default.JoystickDeadzone);
context.DS4[DS4Controller.LeftThumbY] = context.Steam.LeftThumbY.GetValue(Settings.Default.JoystickDeadzone);
context.DS4[DS4Controller.RightThumbX] = context.Steam.RightThumbX.GetValue(Settings.Default.JoystickDeadzone);
context.DS4[DS4Controller.RightThumbY] = context.Steam.RightThumbY.GetValue(Settings.Default.JoystickDeadzone);
context.DS4[DS4Controller.ThumbLeft] = context.Steam.BtnLeftStickPress;
context.DS4[DS4Controller.ThumbRight] = context.Steam.BtnRightStickPress;
@ -135,8 +135,8 @@ namespace SteamController.Profiles.Predefined
if (x || y)
{
return new Point(
(int)x.GetDeltaValue(0, 1920, DeltaValueMode.Absolute),
(int)y.GetDeltaValue(943 + 488, -488, DeltaValueMode.Absolute)
(int)x.GetDeltaValue(0, 1920, DeltaValueMode.Absolute, 0),
(int)y.GetDeltaValue(943 + 488, -488, DeltaValueMode.Absolute, 0)
);
}
else

View file

@ -68,11 +68,23 @@ namespace SteamController.Profiles.Predefined
{
if (c.Steam.LeftThumbX)
{
c.Mouse.HorizontalScroll(c.Steam.LeftThumbX.DeltaValue * Context.ThumbToWhellSensitivity);
c.Mouse.HorizontalScroll(
c.Steam.LeftThumbX.GetDeltaValue(
Context.ThumbToWhellSensitivity,
Devices.DeltaValueMode.AbsoluteTime,
Settings.Default.DesktopJoystickDeadzone
)
);
}
if (c.Steam.LeftThumbY)
{
c.Mouse.VerticalScroll(c.Steam.LeftThumbY.DeltaValue * Context.ThumbToWhellSensitivity * (double)Settings.Default.ScrollDirection);
c.Mouse.VerticalScroll(
c.Steam.LeftThumbY.GetDeltaValue(
Context.ThumbToWhellSensitivity * (double)Settings.Default.ScrollDirection,
Devices.DeltaValueMode.AbsoluteTime,
Settings.Default.DesktopJoystickDeadzone
)
);
}
}

View file

@ -88,10 +88,10 @@ namespace SteamController.Profiles.Predefined
context.X360[Xbox360Button.Y] = context.Steam.BtnY;
// Sticks
context.X360[Xbox360Axis.LeftThumbX] = context.Steam.LeftThumbX;
context.X360[Xbox360Axis.LeftThumbY] = context.Steam.LeftThumbY;
context.X360[Xbox360Axis.RightThumbX] = context.Steam.RightThumbX;
context.X360[Xbox360Axis.RightThumbY] = context.Steam.RightThumbY;
context.X360[Xbox360Axis.LeftThumbX] = context.Steam.LeftThumbX.GetValue(Settings.Default.JoystickDeadzone);
context.X360[Xbox360Axis.LeftThumbY] = context.Steam.LeftThumbY.GetValue(Settings.Default.JoystickDeadzone);
context.X360[Xbox360Axis.RightThumbX] = context.Steam.RightThumbX.GetValue(Settings.Default.JoystickDeadzone);
context.X360[Xbox360Axis.RightThumbY] = context.Steam.RightThumbY.GetValue(Settings.Default.JoystickDeadzone);
context.X360[Xbox360Button.LeftThumb] = context.Steam.BtnLeftStickPress;
context.X360[Xbox360Button.RightThumb] = context.Steam.BtnRightStickPress;

View file

@ -3,7 +3,7 @@ using System.Configuration;
namespace SteamController.ProfilesSettings
{
[Category("Shortcuts")]
[Category("2. Shortcuts")]
internal abstract class BackPanelSettings : CommonHelpers.BaseSettings
{
private const String MappingsDescription = @"Only some of those keys do work. Allowed shortcuts are to be changed in future release.";

View file

@ -3,7 +3,7 @@ using System.Configuration;
namespace SteamController.ProfilesSettings
{
[Category("Settings")]
[Category("3. Haptic")]
internal sealed class HapticSettings : CommonHelpers.BaseSettings
{
public const sbyte MinIntensity = -2;

View file

@ -3,7 +3,7 @@ using System.Configuration;
namespace SteamController
{
[Category("Settings")]
[Category("1. Settings")]
[TypeConverter(typeof(ExpandableObjectConverter))]
internal sealed partial class Settings : CommonHelpers.BaseSettings
{
@ -102,6 +102,20 @@ namespace SteamController
set { Set("KeyboardStyle", value); }
}
[Browsable(false)]
public short DesktopJoystickDeadzone
{
get { return 5000; }
}
[Browsable(true)]
[Description("Deadzone for Left and Right sticks. Enter a number between 0 and 32767. If this number is too small you may experience drift. 5000 or smaller is recommended.")]
public short JoystickDeadzone
{
get { return Get<short>("JoystickDeadZone", 5000); }
set { Set("JoystickDeadZone", value); }
}
public override string ToString()
{
return "";

View file

@ -3,7 +3,7 @@ using System.Configuration;
namespace SteamController
{
[Category("Settings")]
[Category("1. Settings")]
[TypeConverter(typeof(ExpandableObjectConverter))]
internal sealed partial class SettingsDebug : CommonHelpers.BaseSettings
{