Add access to game keypress state buffer

This commit is contained in:
meli 2020-03-28 11:25:12 -07:00
parent 68af40d9fc
commit eec77ac239
3 changed files with 73 additions and 0 deletions

View file

@ -80,6 +80,11 @@ namespace Dalamud.Game.ClientState
/// </summary>
public JobGauges JobGauges;
/// <summary>
/// Provides access to the keypress state of keyboard keys in game.
/// </summary>
public KeyState KeyState;
/// <summary>
/// Set up client state access.
/// </summary>
@ -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<SetupTerritoryTypeDelegate>(Address.SetupTerritoryType,

View file

@ -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;
}
}
}

View file

@ -0,0 +1,62 @@
using Serilog;
using System;
using System.Runtime.InteropServices;
namespace Dalamud.Game.ClientState
{
/// <summary>
/// Wrapper around the game keystate buffer, which contains the pressed state for
/// all keyboard keys, indexed by virtual vkCode
/// </summary>
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}");
}
/// <summary>
/// Get or set the keypressed state for a given vkCode.
/// </summary>
/// <param name="vkCode">The virtual key to change.</param>
/// <returns>Whether the specified key is currently pressed.</returns>
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);
}
}
/// <summary>
/// Clears the pressed state for all keys.
/// </summary>
public void ClearAll()
{
for (var i = 0; i < MaxKeyCodeIndex; i++)
{
Marshal.WriteInt32(this.bufferBase + (i * 4), 0);
}
}
}
}