mirror of
https://github.com/goatcorp/Dalamud.git
synced 2025-12-31 21:03:43 +01:00
feat: get/set raw value, fix indexing after 127
This commit is contained in:
parent
de83a799ae
commit
bb3ec9d408
2 changed files with 110 additions and 24 deletions
|
|
@ -47,6 +47,11 @@ namespace Dalamud.Game.ClientState
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IntPtr KeyboardState { get; private set; }
|
public IntPtr KeyboardState { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the address of the keyboard state index array which translates the VK enumeration to the key state.
|
||||||
|
/// </summary>
|
||||||
|
public IntPtr KeyboardStateIndexArray { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the address of the target manager.
|
/// Gets the address of the target manager.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -93,9 +98,11 @@ namespace Dalamud.Game.ClientState
|
||||||
|
|
||||||
this.SetupTerritoryType = sig.ScanText("48 89 5C 24 ?? 48 89 74 24 ?? 57 48 83 EC 20 48 8B F9 66 89 91 ?? ?? ?? ??");
|
this.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,
|
// These resolve to fixed offsets only, without the base address added in, so GetStaticAddressFromSig() can't be used.
|
||||||
// so GetStaticAddressFromSig() can't be used. lea rcx, ds:1DB9F74h[rax*4]
|
// lea rcx, ds:1DB9F74h[rax*4] KeyboardState
|
||||||
|
// 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.ConditionFlags = sig.GetStaticAddressFromSig("48 8D 0D ?? ?? ?? ?? BA ?? ?? ?? ?? E8 ?? ?? ?? ?? B0 01 48 83 C4 30");
|
this.ConditionFlags = sig.GetStaticAddressFromSig("48 8D 0D ?? ?? ?? ?? BA ?? ?? ?? ?? E8 ?? ?? ?? ?? B0 01 48 83 C4 30");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
using Dalamud.IoC;
|
using Dalamud.IoC;
|
||||||
|
|
@ -10,6 +11,15 @@ namespace Dalamud.Game.ClientState.Keys
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Wrapper around the game keystate buffer, which contains the pressed state for all keyboard keys, indexed by virtual vkCode.
|
/// Wrapper around the game keystate buffer, which contains the pressed state for all keyboard keys, indexed by virtual vkCode.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// The stored key state is actually a combination field, however the below ephemeral states are consumed each frame. Setting
|
||||||
|
/// the value may be mildly useful, however retrieving the value is largely pointless. In testing, it wasn't possible without
|
||||||
|
/// setting the statue manually.
|
||||||
|
/// index & 0 = key pressed.
|
||||||
|
/// index & 1 = key down (ephemeral).
|
||||||
|
/// index & 2 = key up (ephemeral).
|
||||||
|
/// index & 3 = short key press (ephemeral).
|
||||||
|
/// </remarks>
|
||||||
[PluginInterface]
|
[PluginInterface]
|
||||||
[InterfaceVersion("1.0")]
|
[InterfaceVersion("1.0")]
|
||||||
public class KeyState
|
public class KeyState
|
||||||
|
|
@ -18,7 +28,9 @@ namespace Dalamud.Game.ClientState.Keys
|
||||||
// but there is other state data past this point, and keys beyond here aren't
|
// but there is other state data past this point, and keys beyond here aren't
|
||||||
// generally valid for most things anyway
|
// generally valid for most things anyway
|
||||||
private const int MaxKeyCodeIndex = 0xA0;
|
private const int MaxKeyCodeIndex = 0xA0;
|
||||||
private IntPtr bufferBase;
|
private readonly IntPtr bufferBase;
|
||||||
|
private readonly IntPtr indexBase;
|
||||||
|
private VirtualKey[] validVirtualKeyCache = null;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="KeyState"/> class.
|
/// Initializes a new instance of the <see cref="KeyState"/> class.
|
||||||
|
|
@ -29,40 +41,74 @@ namespace Dalamud.Game.ClientState.Keys
|
||||||
var moduleBaseAddress = Service<SigScanner>.Get().Module.BaseAddress;
|
var moduleBaseAddress = Service<SigScanner>.Get().Module.BaseAddress;
|
||||||
|
|
||||||
this.bufferBase = moduleBaseAddress + Marshal.ReadInt32(addressResolver.KeyboardState);
|
this.bufferBase = moduleBaseAddress + Marshal.ReadInt32(addressResolver.KeyboardState);
|
||||||
|
this.indexBase = moduleBaseAddress + Marshal.ReadInt32(addressResolver.KeyboardStateIndexArray);
|
||||||
|
|
||||||
Log.Verbose($"Keyboard state buffer address 0x{this.bufferBase.ToInt64():X}");
|
Log.Verbose($"Keyboard state buffer address 0x{this.bufferBase.ToInt64():X}");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get or set the keypressed state for a given vkCode.
|
/// Get or set the key-pressed state for a given vkCode.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="vkCode">The virtual key to change.</param>
|
/// <param name="vkCode">The virtual key to change.</param>
|
||||||
/// <returns>Whether the specified key is currently pressed.</returns>
|
/// <returns>Whether the specified key is currently pressed.</returns>
|
||||||
public bool this[int vkCode]
|
/// <exception cref="ArgumentException">If the vkCode is not valid. Refer to <see cref="IsVirtualKeyValid(int)"/> or <see cref="GetValidVirtualKeys"/>.</exception>
|
||||||
|
public unsafe bool this[int vkCode]
|
||||||
{
|
{
|
||||||
get
|
get => this.GetRawValue(vkCode) != 0;
|
||||||
{
|
set => this.SetRawValue(vkCode, value ? 1 : 0);
|
||||||
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;
|
/// <inheritdoc cref="this[int]"/>
|
||||||
}
|
public bool this[VirtualKey vkCode]
|
||||||
|
{
|
||||||
set
|
get => this[(int)vkCode];
|
||||||
{
|
set => this[(int)vkCode] = value;
|
||||||
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>
|
/// <summary>
|
||||||
/// Get or set the keypressed state for a given VirtualKey enum.
|
/// Gets the value in the index array.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="vk">The virtual key to change.</param>
|
/// <param name="vkCode">The virtual key to change.</param>
|
||||||
/// <returns>Whether the specified key is currently pressed.</returns>
|
/// <returns>The raw value stored in the index array.</returns>
|
||||||
public bool this[VirtualKey vk] => this[(int)vk];
|
/// <exception cref="ArgumentException">If the vkCode is not valid. Refer to <see cref="IsVirtualKeyValid(int)"/> or <see cref="GetValidVirtualKeys"/>.</exception>
|
||||||
|
public int GetRawValue(int vkCode)
|
||||||
|
=> this.GetRefValue(vkCode);
|
||||||
|
|
||||||
|
/// <inheritdoc cref="GetRawValue(int)"/>
|
||||||
|
public int GetRawValue(VirtualKey vkCode)
|
||||||
|
=> this.GetRawValue((int)vkCode);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the value in the index array.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="vkCode">The virtual key to change.</param>
|
||||||
|
/// <param name="value">The raw value to set in the index array.</param>
|
||||||
|
/// <exception cref="ArgumentException">If the vkCode is not valid. Refer to <see cref="IsVirtualKeyValid(int)"/> or <see cref="GetValidVirtualKeys"/>.</exception>
|
||||||
|
public void SetRawValue(int vkCode, int value)
|
||||||
|
=> this.GetRefValue(vkCode) = value;
|
||||||
|
|
||||||
|
/// <inheritdoc cref="SetRawValue(int, int)"/>
|
||||||
|
public void SetRawValue(VirtualKey vkCode, int value)
|
||||||
|
=> this.SetRawValue((int)vkCode, value);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating whether the given VirtualKey code is regarded as valid input by the game.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="vkCode">Virtual key code.</param>
|
||||||
|
/// <returns>If the code is valid.</returns>
|
||||||
|
public bool IsVirtualKeyValid(int vkCode)
|
||||||
|
=> vkCode > 0 && vkCode < MaxKeyCodeIndex && this.ConvertVirtualKey(vkCode) != 0;
|
||||||
|
|
||||||
|
/// <inheritdoc cref="IsVirtualKeyValid(int)"/>
|
||||||
|
public bool IsVirtualKeyValid(VirtualKey vkCode)
|
||||||
|
=> this.IsVirtualKeyValid((int)vkCode);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets an array of virtual keys the game considers valid input.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>An array of valid virtual keys.</returns>
|
||||||
|
public VirtualKey[] GetValidVirtualKeys()
|
||||||
|
=> this.validVirtualKeyCache ??= Enum.GetValues<VirtualKey>().Where(vk => this.IsVirtualKeyValid(vk)).ToArray();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Clears the pressed state for all keys.
|
/// Clears the pressed state for all keys.
|
||||||
|
|
@ -71,8 +117,41 @@ namespace Dalamud.Game.ClientState.Keys
|
||||||
{
|
{
|
||||||
for (var i = 0; i < MaxKeyCodeIndex; i++)
|
for (var i = 0; i < MaxKeyCodeIndex; i++)
|
||||||
{
|
{
|
||||||
Marshal.WriteInt32(this.bufferBase + (i * 4), 0);
|
this.GetRefValue(i) = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts a virtual key into the equivalent value that the game uses.
|
||||||
|
/// Valid values are non-zero.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="vkCode">Virtual key.</param>
|
||||||
|
/// <returns>Converted value.</returns>
|
||||||
|
private unsafe byte ConvertVirtualKey(int vkCode)
|
||||||
|
{
|
||||||
|
if (vkCode <= 0 || vkCode >= 240)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return *(byte*)(this.indexBase + vkCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the raw value from the key state array.
|
||||||
|
/// No bounds checking is done.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="vkCode">Virtual key code.</param>
|
||||||
|
/// <returns>A reference to the indexed array.</returns>
|
||||||
|
private unsafe ref int GetRefValue(int vkCode)
|
||||||
|
{
|
||||||
|
if (vkCode < 0 || vkCode > MaxKeyCodeIndex)
|
||||||
|
throw new ArgumentException($"Keycode state is only valid up to {MaxKeyCodeIndex}");
|
||||||
|
|
||||||
|
vkCode = this.ConvertVirtualKey(vkCode);
|
||||||
|
|
||||||
|
if (vkCode == 0)
|
||||||
|
throw new ArgumentException($"Keycode state is only valid for certain values. Reference GetValidVirtualKeys for help.");
|
||||||
|
|
||||||
|
return ref *(int*)(this.bufferBase + (4 * vkCode));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue