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);
+ }
+ }
+ }
+}