From eec77ac23963866012689b57b80a08d4f774b76e Mon Sep 17 00:00:00 2001 From: meli <57847713+ff-meli@users.noreply.github.com> Date: Sat, 28 Mar 2020 11:25:12 -0700 Subject: [PATCH] Add access to game keypress state buffer --- Dalamud/Game/ClientState/ClientState.cs | 7 +++ .../ClientState/ClientStateAddressResolver.cs | 4 ++ Dalamud/Game/ClientState/KeyState.cs | 62 +++++++++++++++++++ 3 files changed, 73 insertions(+) create mode 100644 Dalamud/Game/ClientState/KeyState.cs diff --git a/Dalamud/Game/ClientState/ClientState.cs b/Dalamud/Game/ClientState/ClientState.cs index 0aed29e98..ca2572fc3 100644 --- a/Dalamud/Game/ClientState/ClientState.cs +++ b/Dalamud/Game/ClientState/ClientState.cs @@ -80,6 +80,11 @@ namespace Dalamud.Game.ClientState /// public JobGauges JobGauges; + /// + /// Provides access to the keypress state of keyboard keys in game. + /// + public KeyState KeyState; + /// /// Set up client state access. /// @@ -98,6 +103,8 @@ namespace Dalamud.Game.ClientState this.JobGauges = new JobGauges(Address); + this.KeyState = new KeyState(Address, scanner.Module.BaseAddress); + Log.Verbose("SetupTerritoryType address {SetupTerritoryType}", Address.SetupTerritoryType); this.setupTerritoryTypeHook = new Hook(Address.SetupTerritoryType, diff --git a/Dalamud/Game/ClientState/ClientStateAddressResolver.cs b/Dalamud/Game/ClientState/ClientStateAddressResolver.cs index 8d6bab2de..fa29d53b9 100644 --- a/Dalamud/Game/ClientState/ClientStateAddressResolver.cs +++ b/Dalamud/Game/ClientState/ClientStateAddressResolver.cs @@ -8,6 +8,7 @@ namespace Dalamud.Game.ClientState public IntPtr ActorTable { get; private set; } public IntPtr LocalContentId { get; private set; } public IntPtr JobGaugeData { get; private set; } + public IntPtr KeyboardState { get; private set; } // Functions public IntPtr SetupTerritoryType { get; private set; } @@ -18,6 +19,9 @@ namespace Dalamud.Game.ClientState JobGaugeData = sig.GetStaticAddressFromSig("E8 ?? ?? ?? ?? FF C6 48 8D 5B 0C", 0xB9) + 0x10; SetupTerritoryType = sig.ScanText("48 89 5C 24 ?? 48 89 74 24 ?? 57 48 83 EC 20 48 8B F9 66 89 91 ?? ?? ?? ??"); + + // This resolves to a fixed offset only, without the base address added in, so GetStaticAddressFromSig() can't be used + KeyboardState = sig.ScanText("48 8D 0C 85 ?? ?? ?? ?? 8B 04 31 85 C2 0F 85") + 0x4; } } } diff --git a/Dalamud/Game/ClientState/KeyState.cs b/Dalamud/Game/ClientState/KeyState.cs new file mode 100644 index 000000000..5ae92c20c --- /dev/null +++ b/Dalamud/Game/ClientState/KeyState.cs @@ -0,0 +1,62 @@ +using Serilog; +using System; +using System.Runtime.InteropServices; + +namespace Dalamud.Game.ClientState +{ + /// + /// Wrapper around the game keystate buffer, which contains the pressed state for + /// all keyboard keys, indexed by virtual vkCode + /// + public class KeyState + { + private IntPtr bufferBase; + + // The array is accessed in a way that this limit doesn't appear to exist + // but there is other state data past this point, and keys beyond here aren't + // generally valid for most things anyway + private const int MaxKeyCodeIndex = 0xA0; + + public KeyState(ClientStateAddressResolver addressResolver, IntPtr moduleBaseAddress) + { + this.bufferBase = moduleBaseAddress + Marshal.ReadInt32(addressResolver.KeyboardState); + + Log.Verbose($"Keyboard state buffer address {this.bufferBase}"); + } + + /// + /// Get or set the keypressed state for a given vkCode. + /// + /// The virtual key to change. + /// Whether the specified key is currently pressed. + public bool this[int vkCode] + { + get + { + if (vkCode< 0 || vkCode > MaxKeyCodeIndex) + throw new ArgumentException($"Keycode state only appears to be valid up to {MaxKeyCodeIndex}"); + + return (Marshal.ReadInt32(this.bufferBase + (4 * vkCode)) != 0); + } + + set + { + if (vkCode < 0 || vkCode > MaxKeyCodeIndex) + throw new ArgumentException($"Keycode state only appears to be valid up to {MaxKeyCodeIndex}"); + + Marshal.WriteInt32(this.bufferBase + (4 * vkCode), value ? 1 : 0); + } + } + + /// + /// Clears the pressed state for all keys. + /// + public void ClearAll() + { + for (var i = 0; i < MaxKeyCodeIndex; i++) + { + Marshal.WriteInt32(this.bufferBase + (i * 4), 0); + } + } + } +}