diff --git a/Dalamud/Game/ClientState/GamePad/GamepadState.cs b/Dalamud/Game/ClientState/GamePad/GamepadState.cs index c72e9c1de..bc5744047 100644 --- a/Dalamud/Game/ClientState/GamePad/GamepadState.cs +++ b/Dalamud/Game/ClientState/GamePad/GamepadState.cs @@ -1,8 +1,10 @@ using System; +using System.Numerics; using Dalamud.Hooking; using Dalamud.IoC; using Dalamud.IoC.Internal; +using Dalamud.Plugin.Services; using ImGuiNET; using Serilog; @@ -16,9 +18,12 @@ namespace Dalamud.Game.ClientState.GamePad; [PluginInterface] [InterfaceVersion("1.0")] [ServiceManager.BlockingEarlyLoadedService] -public unsafe class GamepadState : IDisposable, IServiceType +#pragma warning disable SA1015 +[ResolveVia] +#pragma warning restore SA1015 +public unsafe class GamepadState : IDisposable, IServiceType, IGamepadState { - private readonly Hook gamepadPoll; + private readonly Hook? gamepadPoll; private bool isDisposed; @@ -42,44 +47,60 @@ public unsafe class GamepadState : IDisposable, IServiceType /// public IntPtr GamepadInputAddress { get; private set; } + /// + public Vector2 LeftStick => + new(this.leftStickX, this.leftStickY); + + /// + public Vector2 RightStick => + new(this.rightStickX, this.rightStickY); + /// /// Gets the state of the left analogue stick in the left direction between 0 (not tilted) and 1 (max tilt). /// + [Obsolete("Use IGamepadState.LeftStick.X", false)] public float LeftStickLeft => this.leftStickX < 0 ? -this.leftStickX / 100f : 0; /// /// Gets the state of the left analogue stick in the right direction between 0 (not tilted) and 1 (max tilt). /// + [Obsolete("Use IGamepadState.LeftStick.X", false)] public float LeftStickRight => this.leftStickX > 0 ? this.leftStickX / 100f : 0; /// /// Gets the state of the left analogue stick in the up direction between 0 (not tilted) and 1 (max tilt). /// + [Obsolete("Use IGamepadState.LeftStick.Y", false)] public float LeftStickUp => this.leftStickY > 0 ? this.leftStickY / 100f : 0; /// /// Gets the state of the left analogue stick in the down direction between 0 (not tilted) and 1 (max tilt). /// + [Obsolete("Use IGamepadState.LeftStick.Y", false)] public float LeftStickDown => this.leftStickY < 0 ? -this.leftStickY / 100f : 0; /// /// Gets the state of the right analogue stick in the left direction between 0 (not tilted) and 1 (max tilt). /// + [Obsolete("Use IGamepadState.RightStick.X", false)] public float RightStickLeft => this.rightStickX < 0 ? -this.rightStickX / 100f : 0; /// /// Gets the state of the right analogue stick in the right direction between 0 (not tilted) and 1 (max tilt). /// + [Obsolete("Use IGamepadState.RightStick.X", false)] public float RightStickRight => this.rightStickX > 0 ? this.rightStickX / 100f : 0; /// /// Gets the state of the right analogue stick in the up direction between 0 (not tilted) and 1 (max tilt). /// + [Obsolete("Use IGamepadState.RightStick.Y", false)] public float RightStickUp => this.rightStickY > 0 ? this.rightStickY / 100f : 0; /// /// Gets the state of the right analogue stick in the down direction between 0 (not tilted) and 1 (max tilt). /// + [Obsolete("Use IGamepadState.RightStick.Y", false)] public float RightStickDown => this.rightStickY < 0 ? -this.rightStickY / 100f : 0; /// @@ -120,43 +141,16 @@ public unsafe class GamepadState : IDisposable, IServiceType /// internal bool NavEnableGamepad { get; set; } - /// - /// Gets whether has been pressed. - /// - /// Only true on first frame of the press. - /// If ImGuiConfigFlags.NavEnableGamepad is set, this is unreliable. - /// - /// The button to check for. - /// 1 if pressed, 0 otherwise. + /// public float Pressed(GamepadButtons button) => (this.ButtonsPressed & (ushort)button) > 0 ? 1 : 0; - /// - /// Gets whether is being pressed. - /// - /// True in intervals if button is held down. - /// If ImGuiConfigFlags.NavEnableGamepad is set, this is unreliable. - /// - /// The button to check for. - /// 1 if still pressed during interval, 0 otherwise or in between intervals. + /// public float Repeat(GamepadButtons button) => (this.ButtonsRepeat & (ushort)button) > 0 ? 1 : 0; - /// - /// Gets whether has been released. - /// - /// Only true the frame after release. - /// If ImGuiConfigFlags.NavEnableGamepad is set, this is unreliable. - /// - /// The button to check for. - /// 1 if released, 0 otherwise. + /// public float Released(GamepadButtons button) => (this.ButtonsReleased & (ushort)button) > 0 ? 1 : 0; - /// - /// Gets the raw state of . - /// - /// Is set the entire time a button is pressed down. - /// - /// The button to check for. - /// 1 the whole time button is pressed, 0 otherwise. + /// public float Raw(GamepadButtons button) => (this.ButtonsRaw & (ushort)button) > 0 ? 1 : 0; /// @@ -171,12 +165,12 @@ public unsafe class GamepadState : IDisposable, IServiceType [ServiceManager.CallWhenServicesReady] private void ContinueConstruction() { - this.gamepadPoll.Enable(); + this.gamepadPoll?.Enable(); } private int GamepadPollDetour(IntPtr gamepadInput) { - var original = this.gamepadPoll.Original(gamepadInput); + var original = this.gamepadPoll!.Original(gamepadInput); try { this.GamepadInputAddress = gamepadInput; diff --git a/Dalamud/Plugin/Services/IGamepadState.cs b/Dalamud/Plugin/Services/IGamepadState.cs new file mode 100644 index 000000000..c349923f3 --- /dev/null +++ b/Dalamud/Plugin/Services/IGamepadState.cs @@ -0,0 +1,68 @@ +using System.Numerics; + +using Dalamud.Game.ClientState.GamePad; +using ImGuiNET; + +namespace Dalamud.Plugin.Services; + +/// +/// Exposes the game gamepad state to dalamud. +/// +/// Will block game's gamepad input if is set. +/// +public interface IGamepadState +{ + /// + /// Gets the pointer to the current instance of the GamepadInput struct. + /// + public nint GamepadInputAddress { get; } + + /// + /// Gets the left analogue sticks tilt vector. + /// + public Vector2 LeftStick { get; } + + /// + /// Gets the right analogue sticks tilt vector. + /// + public Vector2 RightStick { get; } + + /// + /// Gets whether has been pressed. + /// + /// Only true on first frame of the press. + /// If ImGuiConfigFlags.NavEnableGamepad is set, this is unreliable. + /// + /// The button to check for. + /// 1 if pressed, 0 otherwise. + public float Pressed(GamepadButtons button); + + /// + /// Gets whether is being pressed. + /// + /// True in intervals if button is held down. + /// If ImGuiConfigFlags.NavEnableGamepad is set, this is unreliable. + /// + /// The button to check for. + /// 1 if still pressed during interval, 0 otherwise or in between intervals. + public float Repeat(GamepadButtons button); + + /// + /// Gets whether has been released. + /// + /// Only true the frame after release. + /// If ImGuiConfigFlags.NavEnableGamepad is set, this is unreliable. + /// + /// The button to check for. + /// 1 if released, 0 otherwise. + public float Released(GamepadButtons button); + + /// + /// Gets the raw state of . + /// + /// Is set the entire time a button is pressed down. + /// + /// The button to check for. + /// 1 the whole time button is pressed, 0 otherwise. + public float Raw(GamepadButtons button); +}