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