diff --git a/Dalamud/Game/ClientState/ClientStateAddressResolver.cs b/Dalamud/Game/ClientState/ClientStateAddressResolver.cs
index d44275ef8..97bc5dae1 100644
--- a/Dalamud/Game/ClientState/ClientStateAddressResolver.cs
+++ b/Dalamud/Game/ClientState/ClientStateAddressResolver.cs
@@ -24,12 +24,6 @@ internal sealed class ClientStateAddressResolver : BaseAddressResolver
///
public IntPtr ProcessPacketPlayerSetup { get; private set; }
- ///
- /// Gets the address of the method which polls the gamepads for data.
- /// Called every frame, even when `Enable Gamepad` is off in the settings.
- ///
- public IntPtr GamepadPoll { get; private set; }
-
///
/// Scan for and setup any configured address pointers.
///
@@ -43,7 +37,5 @@ internal sealed class ClientStateAddressResolver : BaseAddressResolver
// movzx edx, byte ptr [rbx+rsi+1D5E0E0h] KeyboardStateIndexArray
this.KeyboardState = sig.ScanText("48 8D 0C 85 ?? ?? ?? ?? 8B 04 31 85 C2 0F 85") + 0x4;
this.KeyboardStateIndexArray = sig.ScanText("0F B6 94 33 ?? ?? ?? ?? 84 D2") + 0x4;
-
- this.GamepadPoll = sig.ScanText("40 55 53 57 41 54 41 57 48 8D AC 24 ?? ?? ?? ?? 48 81 EC ?? ?? ?? ?? 44 0F 29 B4 24"); // unnamed in cs
}
}
diff --git a/Dalamud/Game/ClientState/GamePad/GamepadInput.cs b/Dalamud/Game/ClientState/GamePad/GamepadInput.cs
deleted file mode 100644
index d9dcea60f..000000000
--- a/Dalamud/Game/ClientState/GamePad/GamepadInput.cs
+++ /dev/null
@@ -1,75 +0,0 @@
-using System.Runtime.InteropServices;
-
-namespace Dalamud.Game.ClientState.GamePad;
-
-///
-/// Struct which gets populated by polling the gamepads.
-///
-/// Has an array of gamepads, among many other things (here not mapped).
-/// All we really care about is the final data which the game uses to determine input.
-///
-/// The size is definitely bigger than only the following fields but I do not know how big.
-///
-[StructLayout(LayoutKind.Explicit)]
-public struct GamepadInput
-{
- ///
- /// Left analogue stick's horizontal value, -99 for left, 99 for right.
- ///
- [FieldOffset(0x78)]
- public int LeftStickX;
-
- ///
- /// Left analogue stick's vertical value, -99 for down, 99 for up.
- ///
- [FieldOffset(0x7C)]
- public int LeftStickY;
-
- ///
- /// Right analogue stick's horizontal value, -99 for left, 99 for right.
- ///
- [FieldOffset(0x80)]
- public int RightStickX;
-
- ///
- /// Right analogue stick's vertical value, -99 for down, 99 for up.
- ///
- [FieldOffset(0x84)]
- public int RightStickY;
-
- ///
- /// Raw input, set the whole time while a button is held. See for the mapping.
- ///
- ///
- /// This is a bitfield.
- ///
- [FieldOffset(0x88)]
- public ushort ButtonsRaw;
-
- ///
- /// Button pressed, set once when the button is pressed. See for the mapping.
- ///
- ///
- /// This is a bitfield.
- ///
- [FieldOffset(0x8C)]
- public ushort ButtonsPressed;
-
- ///
- /// Button released input, set once right after the button is not hold anymore. See for the mapping.
- ///
- ///
- /// This is a bitfield.
- ///
- [FieldOffset(0x90)]
- public ushort ButtonsReleased;
-
- ///
- /// Repeatedly emits the held button input in fixed intervals. See for the mapping.
- ///
- ///
- /// This is a bitfield.
- ///
- [FieldOffset(0x94)]
- public ushort ButtonsRepeat;
-}
diff --git a/Dalamud/Game/ClientState/GamePad/GamepadState.cs b/Dalamud/Game/ClientState/GamePad/GamepadState.cs
index 05d691823..5237c6f0c 100644
--- a/Dalamud/Game/ClientState/GamePad/GamepadState.cs
+++ b/Dalamud/Game/ClientState/GamePad/GamepadState.cs
@@ -4,7 +4,8 @@ using Dalamud.Hooking;
using Dalamud.IoC;
using Dalamud.IoC.Internal;
using Dalamud.Plugin.Services;
-using Dalamud.Utility;
+
+using FFXIVClientStructs.FFXIV.Client.System.Input;
using ImGuiNET;
using Serilog;
@@ -23,7 +24,7 @@ namespace Dalamud.Game.ClientState.GamePad;
#pragma warning restore SA1015
internal unsafe class GamepadState : IInternalDisposableService, IGamepadState
{
- private readonly Hook? gamepadPoll;
+ private readonly Hook? gamepadPoll;
private bool isDisposed;
@@ -35,25 +36,21 @@ internal unsafe class GamepadState : IInternalDisposableService, IGamepadState
[ServiceManager.ServiceConstructor]
private GamepadState(ClientState clientState)
{
- var resolver = clientState.AddressResolver;
- Log.Verbose($"GamepadPoll address {Util.DescribeAddress(resolver.GamepadPoll)}");
- this.gamepadPoll = Hook.FromAddress(resolver.GamepadPoll, this.GamepadPollDetour);
+ this.gamepadPoll = Hook.FromAddress((nint)PadDevice.StaticVirtualTablePointer->Poll, this.GamepadPollDetour);
this.gamepadPoll?.Enable();
}
- private delegate int ControllerPoll(IntPtr controllerInput);
-
///
/// Gets the pointer to the current instance of the GamepadInput struct.
///
public IntPtr GamepadInputAddress { get; private set; }
///
- public Vector2 LeftStick =>
+ public Vector2 LeftStick =>
new(this.leftStickX, this.leftStickY);
-
+
///
- public Vector2 RightStick =>
+ public Vector2 RightStick =>
new(this.rightStickX, this.rightStickY);
///
@@ -61,28 +58,28 @@ internal unsafe class GamepadState : IInternalDisposableService, IGamepadState
///
/// Exposed internally for Debug Data window.
///
- internal ushort ButtonsPressed { get; private set; }
+ internal GamepadButtons ButtonsPressed { get; private set; }
///
/// Gets raw button bitmask, set the whole time while a button is held. See for the mapping.
///
/// Exposed internally for Debug Data window.
///
- internal ushort ButtonsRaw { get; private set; }
+ internal GamepadButtons ButtonsRaw { get; private set; }
///
/// Gets button released bitmask, set once right after the button is not hold anymore. See for the mapping.
///
/// Exposed internally for Debug Data window.
///
- internal ushort ButtonsReleased { get; private set; }
+ internal GamepadButtons ButtonsReleased { get; private set; }
///
/// Gets button repeat bitmask, emits the held button input in fixed intervals. See for the mapping.
///
/// Exposed internally for Debug Data window.
///
- internal ushort ButtonsRepeat { get; private set; }
+ internal GamepadButtons ButtonsRepeat { get; private set; }
///
/// Gets or sets a value indicating whether detour should block gamepad input for game.
@@ -95,16 +92,16 @@ internal unsafe class GamepadState : IInternalDisposableService, IGamepadState
internal bool NavEnableGamepad { get; set; }
///
- public float Pressed(GamepadButtons button) => (this.ButtonsPressed & (ushort)button) > 0 ? 1 : 0;
+ public float Pressed(GamepadButtons button) => (this.ButtonsPressed & button) > 0 ? 1 : 0;
///
- public float Repeat(GamepadButtons button) => (this.ButtonsRepeat & (ushort)button) > 0 ? 1 : 0;
+ public float Repeat(GamepadButtons button) => (this.ButtonsRepeat & button) > 0 ? 1 : 0;
///
- public float Released(GamepadButtons button) => (this.ButtonsReleased & (ushort)button) > 0 ? 1 : 0;
+ public float Released(GamepadButtons button) => (this.ButtonsReleased & button) > 0 ? 1 : 0;
///
- public float Raw(GamepadButtons button) => (this.ButtonsRaw & (ushort)button) > 0 ? 1 : 0;
+ public float Raw(GamepadButtons button) => (this.ButtonsRaw & button) > 0 ? 1 : 0;
///
/// Disposes this instance, alongside its hooks.
@@ -115,28 +112,28 @@ internal unsafe class GamepadState : IInternalDisposableService, IGamepadState
GC.SuppressFinalize(this);
}
- private int GamepadPollDetour(IntPtr gamepadInput)
+ private nint GamepadPollDetour(PadDevice* gamepadInput)
{
var original = this.gamepadPoll!.Original(gamepadInput);
try
{
- this.GamepadInputAddress = gamepadInput;
- var input = (GamepadInput*)gamepadInput;
- this.leftStickX = input->LeftStickX;
- this.leftStickY = input->LeftStickY;
- this.rightStickX = input->RightStickX;
- this.rightStickY = input->RightStickY;
- this.ButtonsRaw = input->ButtonsRaw;
- this.ButtonsPressed = input->ButtonsPressed;
- this.ButtonsReleased = input->ButtonsReleased;
- this.ButtonsRepeat = input->ButtonsRepeat;
+ this.GamepadInputAddress = (nint)gamepadInput;
+
+ this.leftStickX = gamepadInput->GamepadInputData.LeftStickX;
+ this.leftStickY = gamepadInput->GamepadInputData.LeftStickY;
+ this.rightStickX = gamepadInput->GamepadInputData.RightStickX;
+ this.rightStickY = gamepadInput->GamepadInputData.RightStickY;
+ this.ButtonsRaw = (GamepadButtons)gamepadInput->GamepadInputData.Buttons;
+ this.ButtonsPressed = (GamepadButtons)gamepadInput->GamepadInputData.ButtonsPressed;
+ this.ButtonsReleased = (GamepadButtons)gamepadInput->GamepadInputData.ButtonsReleased;
+ this.ButtonsRepeat = (GamepadButtons)gamepadInput->GamepadInputData.ButtonsRepeat;
if (this.NavEnableGamepad)
{
- input->LeftStickX = 0;
- input->LeftStickY = 0;
- input->RightStickX = 0;
- input->RightStickY = 0;
+ gamepadInput->GamepadInputData.LeftStickX = 0;
+ gamepadInput->GamepadInputData.LeftStickY = 0;
+ gamepadInput->GamepadInputData.RightStickX = 0;
+ gamepadInput->GamepadInputData.RightStickY = 0;
// NOTE (Chiv) Zeroing `ButtonsRaw` destroys `ButtonPressed`, `ButtonReleased`
// and `ButtonRepeat` as the game uses the RAW input to determine those (apparently).
@@ -153,16 +150,16 @@ internal unsafe class GamepadState : IInternalDisposableService, IGamepadState
// `ButtonPressed` while ImGuiConfigFlags.NavEnableGamepad is set.
// This is debatable.
// ImGui itself does not care either way as it uses the Raw values and does its own state handling.
- const ushort deletionMask = (ushort)(~GamepadButtons.L2
- & ~GamepadButtons.R2
- & ~GamepadButtons.DpadDown
- & ~GamepadButtons.DpadLeft
- & ~GamepadButtons.DpadUp
- & ~GamepadButtons.DpadRight);
- input->ButtonsRaw &= deletionMask;
- input->ButtonsPressed = 0;
- input->ButtonsReleased = 0;
- input->ButtonsRepeat = 0;
+ const GamepadButtonsFlags deletionMask = ~GamepadButtonsFlags.L2
+ & ~GamepadButtonsFlags.R2
+ & ~GamepadButtonsFlags.DPadDown
+ & ~GamepadButtonsFlags.DPadLeft
+ & ~GamepadButtonsFlags.DPadUp
+ & ~GamepadButtonsFlags.DPadRight;
+ gamepadInput->GamepadInputData.Buttons &= deletionMask;
+ gamepadInput->GamepadInputData.ButtonsPressed = 0;
+ gamepadInput->GamepadInputData.ButtonsReleased = 0;
+ gamepadInput->GamepadInputData.ButtonsRepeat = 0;
return 0;
}
diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/GamepadWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/GamepadWidget.cs
index 5121d82e6..610fa90cc 100644
--- a/Dalamud/Interface/Internal/Windows/Data/Widgets/GamepadWidget.cs
+++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/GamepadWidget.cs
@@ -12,9 +12,9 @@ internal class GamepadWidget : IDataWindowWidget
{
///
public string[]? CommandShortcuts { get; init; } = { "gamepad", "controller" };
-
+
///
- public string DisplayName { get; init; } = "Gamepad";
+ public string DisplayName { get; init; } = "Gamepad";
///
public bool Ready { get; set; }
@@ -42,24 +42,24 @@ internal class GamepadWidget : IDataWindowWidget
this.DrawHelper(
"Buttons Raw",
- gamepadState.ButtonsRaw,
+ (uint)gamepadState.ButtonsRaw,
gamepadState.Raw);
this.DrawHelper(
"Buttons Pressed",
- gamepadState.ButtonsPressed,
+ (uint)gamepadState.ButtonsPressed,
gamepadState.Pressed);
this.DrawHelper(
"Buttons Repeat",
- gamepadState.ButtonsRepeat,
+ (uint)gamepadState.ButtonsRepeat,
gamepadState.Repeat);
this.DrawHelper(
"Buttons Released",
- gamepadState.ButtonsReleased,
+ (uint)gamepadState.ButtonsReleased,
gamepadState.Released);
ImGui.Text($"LeftStick {gamepadState.LeftStick}");
ImGui.Text($"RightStick {gamepadState.RightStick}");
}
-
+
private void DrawHelper(string text, uint mask, Func resolve)
{
ImGui.Text($"{text} {mask:X4}");
diff --git a/lib/FFXIVClientStructs b/lib/FFXIVClientStructs
index 3c99b4f8f..48076a4ce 160000
--- a/lib/FFXIVClientStructs
+++ b/lib/FFXIVClientStructs
@@ -1 +1 @@
-Subproject commit 3c99b4f8f7f56ee4defd3ee75809c73312359f9e
+Subproject commit 48076a4ce750c8f008f3bedd04d0bced03147f56