mirror of
https://github.com/goatcorp/Dalamud.git
synced 2025-12-12 18:27:23 +01:00
update clientstructs
- fix broken gamepad sig by delegating to CS
This commit is contained in:
parent
445fe09181
commit
919ca87bbe
5 changed files with 48 additions and 134 deletions
|
|
@ -24,12 +24,6 @@ internal sealed class ClientStateAddressResolver : BaseAddressResolver
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IntPtr ProcessPacketPlayerSetup { get; private set; }
|
public IntPtr ProcessPacketPlayerSetup { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the address of the method which polls the gamepads for data.
|
|
||||||
/// Called every frame, even when `Enable Gamepad` is off in the settings.
|
|
||||||
/// </summary>
|
|
||||||
public IntPtr GamepadPoll { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Scan for and setup any configured address pointers.
|
/// Scan for and setup any configured address pointers.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -43,7 +37,5 @@ internal sealed class ClientStateAddressResolver : BaseAddressResolver
|
||||||
// movzx edx, byte ptr [rbx+rsi+1D5E0E0h] KeyboardStateIndexArray
|
// 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.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.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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,75 +0,0 @@
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
namespace Dalamud.Game.ClientState.GamePad;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 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.
|
|
||||||
/// </summary>
|
|
||||||
[StructLayout(LayoutKind.Explicit)]
|
|
||||||
public struct GamepadInput
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Left analogue stick's horizontal value, -99 for left, 99 for right.
|
|
||||||
/// </summary>
|
|
||||||
[FieldOffset(0x78)]
|
|
||||||
public int LeftStickX;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Left analogue stick's vertical value, -99 for down, 99 for up.
|
|
||||||
/// </summary>
|
|
||||||
[FieldOffset(0x7C)]
|
|
||||||
public int LeftStickY;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Right analogue stick's horizontal value, -99 for left, 99 for right.
|
|
||||||
/// </summary>
|
|
||||||
[FieldOffset(0x80)]
|
|
||||||
public int RightStickX;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Right analogue stick's vertical value, -99 for down, 99 for up.
|
|
||||||
/// </summary>
|
|
||||||
[FieldOffset(0x84)]
|
|
||||||
public int RightStickY;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Raw input, set the whole time while a button is held. See <see cref="GamepadButtons"/> for the mapping.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// This is a bitfield.
|
|
||||||
/// </remarks>
|
|
||||||
[FieldOffset(0x88)]
|
|
||||||
public ushort ButtonsRaw;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Button pressed, set once when the button is pressed. See <see cref="GamepadButtons"/> for the mapping.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// This is a bitfield.
|
|
||||||
/// </remarks>
|
|
||||||
[FieldOffset(0x8C)]
|
|
||||||
public ushort ButtonsPressed;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Button released input, set once right after the button is not hold anymore. See <see cref="GamepadButtons"/> for the mapping.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// This is a bitfield.
|
|
||||||
/// </remarks>
|
|
||||||
[FieldOffset(0x90)]
|
|
||||||
public ushort ButtonsReleased;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Repeatedly emits the held button input in fixed intervals. See <see cref="GamepadButtons"/> for the mapping.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// This is a bitfield.
|
|
||||||
/// </remarks>
|
|
||||||
[FieldOffset(0x94)]
|
|
||||||
public ushort ButtonsRepeat;
|
|
||||||
}
|
|
||||||
|
|
@ -4,7 +4,8 @@ using Dalamud.Hooking;
|
||||||
using Dalamud.IoC;
|
using Dalamud.IoC;
|
||||||
using Dalamud.IoC.Internal;
|
using Dalamud.IoC.Internal;
|
||||||
using Dalamud.Plugin.Services;
|
using Dalamud.Plugin.Services;
|
||||||
using Dalamud.Utility;
|
|
||||||
|
using FFXIVClientStructs.FFXIV.Client.System.Input;
|
||||||
|
|
||||||
using ImGuiNET;
|
using ImGuiNET;
|
||||||
using Serilog;
|
using Serilog;
|
||||||
|
|
@ -23,7 +24,7 @@ namespace Dalamud.Game.ClientState.GamePad;
|
||||||
#pragma warning restore SA1015
|
#pragma warning restore SA1015
|
||||||
internal unsafe class GamepadState : IInternalDisposableService, IGamepadState
|
internal unsafe class GamepadState : IInternalDisposableService, IGamepadState
|
||||||
{
|
{
|
||||||
private readonly Hook<ControllerPoll>? gamepadPoll;
|
private readonly Hook<PadDevice.Delegates.Poll>? gamepadPoll;
|
||||||
|
|
||||||
private bool isDisposed;
|
private bool isDisposed;
|
||||||
|
|
||||||
|
|
@ -35,25 +36,21 @@ internal unsafe class GamepadState : IInternalDisposableService, IGamepadState
|
||||||
[ServiceManager.ServiceConstructor]
|
[ServiceManager.ServiceConstructor]
|
||||||
private GamepadState(ClientState clientState)
|
private GamepadState(ClientState clientState)
|
||||||
{
|
{
|
||||||
var resolver = clientState.AddressResolver;
|
this.gamepadPoll = Hook<PadDevice.Delegates.Poll>.FromAddress((nint)PadDevice.StaticVirtualTablePointer->Poll, this.GamepadPollDetour);
|
||||||
Log.Verbose($"GamepadPoll address {Util.DescribeAddress(resolver.GamepadPoll)}");
|
|
||||||
this.gamepadPoll = Hook<ControllerPoll>.FromAddress(resolver.GamepadPoll, this.GamepadPollDetour);
|
|
||||||
this.gamepadPoll?.Enable();
|
this.gamepadPoll?.Enable();
|
||||||
}
|
}
|
||||||
|
|
||||||
private delegate int ControllerPoll(IntPtr controllerInput);
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the pointer to the current instance of the GamepadInput struct.
|
/// Gets the pointer to the current instance of the GamepadInput struct.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IntPtr GamepadInputAddress { get; private set; }
|
public IntPtr GamepadInputAddress { get; private set; }
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public Vector2 LeftStick =>
|
public Vector2 LeftStick =>
|
||||||
new(this.leftStickX, this.leftStickY);
|
new(this.leftStickX, this.leftStickY);
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public Vector2 RightStick =>
|
public Vector2 RightStick =>
|
||||||
new(this.rightStickX, this.rightStickY);
|
new(this.rightStickX, this.rightStickY);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -61,28 +58,28 @@ internal unsafe class GamepadState : IInternalDisposableService, IGamepadState
|
||||||
///
|
///
|
||||||
/// Exposed internally for Debug Data window.
|
/// Exposed internally for Debug Data window.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal ushort ButtonsPressed { get; private set; }
|
internal GamepadButtons ButtonsPressed { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets raw button bitmask, set the whole time while a button is held. See <see cref="GamepadButtons"/> for the mapping.
|
/// Gets raw button bitmask, set the whole time while a button is held. See <see cref="GamepadButtons"/> for the mapping.
|
||||||
///
|
///
|
||||||
/// Exposed internally for Debug Data window.
|
/// Exposed internally for Debug Data window.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal ushort ButtonsRaw { get; private set; }
|
internal GamepadButtons ButtonsRaw { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets button released bitmask, set once right after the button is not hold anymore. See <see cref="GamepadButtons"/> for the mapping.
|
/// Gets button released bitmask, set once right after the button is not hold anymore. See <see cref="GamepadButtons"/> for the mapping.
|
||||||
///
|
///
|
||||||
/// Exposed internally for Debug Data window.
|
/// Exposed internally for Debug Data window.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal ushort ButtonsReleased { get; private set; }
|
internal GamepadButtons ButtonsReleased { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets button repeat bitmask, emits the held button input in fixed intervals. See <see cref="GamepadButtons"/> for the mapping.
|
/// Gets button repeat bitmask, emits the held button input in fixed intervals. See <see cref="GamepadButtons"/> for the mapping.
|
||||||
///
|
///
|
||||||
/// Exposed internally for Debug Data window.
|
/// Exposed internally for Debug Data window.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal ushort ButtonsRepeat { get; private set; }
|
internal GamepadButtons ButtonsRepeat { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets a value indicating whether detour should block gamepad input for game.
|
/// 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; }
|
internal bool NavEnableGamepad { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public float Pressed(GamepadButtons button) => (this.ButtonsPressed & (ushort)button) > 0 ? 1 : 0;
|
public float Pressed(GamepadButtons button) => (this.ButtonsPressed & button) > 0 ? 1 : 0;
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public float Repeat(GamepadButtons button) => (this.ButtonsRepeat & (ushort)button) > 0 ? 1 : 0;
|
public float Repeat(GamepadButtons button) => (this.ButtonsRepeat & button) > 0 ? 1 : 0;
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public float Released(GamepadButtons button) => (this.ButtonsReleased & (ushort)button) > 0 ? 1 : 0;
|
public float Released(GamepadButtons button) => (this.ButtonsReleased & button) > 0 ? 1 : 0;
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public float Raw(GamepadButtons button) => (this.ButtonsRaw & (ushort)button) > 0 ? 1 : 0;
|
public float Raw(GamepadButtons button) => (this.ButtonsRaw & button) > 0 ? 1 : 0;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Disposes this instance, alongside its hooks.
|
/// Disposes this instance, alongside its hooks.
|
||||||
|
|
@ -115,28 +112,28 @@ internal unsafe class GamepadState : IInternalDisposableService, IGamepadState
|
||||||
GC.SuppressFinalize(this);
|
GC.SuppressFinalize(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private int GamepadPollDetour(IntPtr gamepadInput)
|
private nint GamepadPollDetour(PadDevice* gamepadInput)
|
||||||
{
|
{
|
||||||
var original = this.gamepadPoll!.Original(gamepadInput);
|
var original = this.gamepadPoll!.Original(gamepadInput);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
this.GamepadInputAddress = gamepadInput;
|
this.GamepadInputAddress = (nint)gamepadInput;
|
||||||
var input = (GamepadInput*)gamepadInput;
|
|
||||||
this.leftStickX = input->LeftStickX;
|
this.leftStickX = gamepadInput->GamepadInputData.LeftStickX;
|
||||||
this.leftStickY = input->LeftStickY;
|
this.leftStickY = gamepadInput->GamepadInputData.LeftStickY;
|
||||||
this.rightStickX = input->RightStickX;
|
this.rightStickX = gamepadInput->GamepadInputData.RightStickX;
|
||||||
this.rightStickY = input->RightStickY;
|
this.rightStickY = gamepadInput->GamepadInputData.RightStickY;
|
||||||
this.ButtonsRaw = input->ButtonsRaw;
|
this.ButtonsRaw = (GamepadButtons)gamepadInput->GamepadInputData.Buttons;
|
||||||
this.ButtonsPressed = input->ButtonsPressed;
|
this.ButtonsPressed = (GamepadButtons)gamepadInput->GamepadInputData.ButtonsPressed;
|
||||||
this.ButtonsReleased = input->ButtonsReleased;
|
this.ButtonsReleased = (GamepadButtons)gamepadInput->GamepadInputData.ButtonsReleased;
|
||||||
this.ButtonsRepeat = input->ButtonsRepeat;
|
this.ButtonsRepeat = (GamepadButtons)gamepadInput->GamepadInputData.ButtonsRepeat;
|
||||||
|
|
||||||
if (this.NavEnableGamepad)
|
if (this.NavEnableGamepad)
|
||||||
{
|
{
|
||||||
input->LeftStickX = 0;
|
gamepadInput->GamepadInputData.LeftStickX = 0;
|
||||||
input->LeftStickY = 0;
|
gamepadInput->GamepadInputData.LeftStickY = 0;
|
||||||
input->RightStickX = 0;
|
gamepadInput->GamepadInputData.RightStickX = 0;
|
||||||
input->RightStickY = 0;
|
gamepadInput->GamepadInputData.RightStickY = 0;
|
||||||
|
|
||||||
// NOTE (Chiv) Zeroing `ButtonsRaw` destroys `ButtonPressed`, `ButtonReleased`
|
// NOTE (Chiv) Zeroing `ButtonsRaw` destroys `ButtonPressed`, `ButtonReleased`
|
||||||
// and `ButtonRepeat` as the game uses the RAW input to determine those (apparently).
|
// 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.
|
// `ButtonPressed` while ImGuiConfigFlags.NavEnableGamepad is set.
|
||||||
// This is debatable.
|
// This is debatable.
|
||||||
// ImGui itself does not care either way as it uses the Raw values and does its own state handling.
|
// 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
|
const GamepadButtonsFlags deletionMask = ~GamepadButtonsFlags.L2
|
||||||
& ~GamepadButtons.R2
|
& ~GamepadButtonsFlags.R2
|
||||||
& ~GamepadButtons.DpadDown
|
& ~GamepadButtonsFlags.DPadDown
|
||||||
& ~GamepadButtons.DpadLeft
|
& ~GamepadButtonsFlags.DPadLeft
|
||||||
& ~GamepadButtons.DpadUp
|
& ~GamepadButtonsFlags.DPadUp
|
||||||
& ~GamepadButtons.DpadRight);
|
& ~GamepadButtonsFlags.DPadRight;
|
||||||
input->ButtonsRaw &= deletionMask;
|
gamepadInput->GamepadInputData.Buttons &= deletionMask;
|
||||||
input->ButtonsPressed = 0;
|
gamepadInput->GamepadInputData.ButtonsPressed = 0;
|
||||||
input->ButtonsReleased = 0;
|
gamepadInput->GamepadInputData.ButtonsReleased = 0;
|
||||||
input->ButtonsRepeat = 0;
|
gamepadInput->GamepadInputData.ButtonsRepeat = 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,9 +12,9 @@ internal class GamepadWidget : IDataWindowWidget
|
||||||
{
|
{
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public string[]? CommandShortcuts { get; init; } = { "gamepad", "controller" };
|
public string[]? CommandShortcuts { get; init; } = { "gamepad", "controller" };
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public string DisplayName { get; init; } = "Gamepad";
|
public string DisplayName { get; init; } = "Gamepad";
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public bool Ready { get; set; }
|
public bool Ready { get; set; }
|
||||||
|
|
@ -42,24 +42,24 @@ internal class GamepadWidget : IDataWindowWidget
|
||||||
|
|
||||||
this.DrawHelper(
|
this.DrawHelper(
|
||||||
"Buttons Raw",
|
"Buttons Raw",
|
||||||
gamepadState.ButtonsRaw,
|
(uint)gamepadState.ButtonsRaw,
|
||||||
gamepadState.Raw);
|
gamepadState.Raw);
|
||||||
this.DrawHelper(
|
this.DrawHelper(
|
||||||
"Buttons Pressed",
|
"Buttons Pressed",
|
||||||
gamepadState.ButtonsPressed,
|
(uint)gamepadState.ButtonsPressed,
|
||||||
gamepadState.Pressed);
|
gamepadState.Pressed);
|
||||||
this.DrawHelper(
|
this.DrawHelper(
|
||||||
"Buttons Repeat",
|
"Buttons Repeat",
|
||||||
gamepadState.ButtonsRepeat,
|
(uint)gamepadState.ButtonsRepeat,
|
||||||
gamepadState.Repeat);
|
gamepadState.Repeat);
|
||||||
this.DrawHelper(
|
this.DrawHelper(
|
||||||
"Buttons Released",
|
"Buttons Released",
|
||||||
gamepadState.ButtonsReleased,
|
(uint)gamepadState.ButtonsReleased,
|
||||||
gamepadState.Released);
|
gamepadState.Released);
|
||||||
ImGui.Text($"LeftStick {gamepadState.LeftStick}");
|
ImGui.Text($"LeftStick {gamepadState.LeftStick}");
|
||||||
ImGui.Text($"RightStick {gamepadState.RightStick}");
|
ImGui.Text($"RightStick {gamepadState.RightStick}");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawHelper(string text, uint mask, Func<GamepadButtons, float> resolve)
|
private void DrawHelper(string text, uint mask, Func<GamepadButtons, float> resolve)
|
||||||
{
|
{
|
||||||
ImGui.Text($"{text} {mask:X4}");
|
ImGui.Text($"{text} {mask:X4}");
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
Subproject commit 3c99b4f8f7f56ee4defd3ee75809c73312359f9e
|
Subproject commit 48076a4ce750c8f008f3bedd04d0bced03147f56
|
||||||
Loading…
Add table
Add a link
Reference in a new issue