From a3e1e1173700b3350c4369fc560fdd6b2e37eccd Mon Sep 17 00:00:00 2001 From: Florian Maunier Date: Wed, 8 Apr 2020 18:27:36 +0200 Subject: [PATCH] Add HandleItemOut hook Allows detecting when no more item is hovered and dispatch event accordingly. Also actually fill the HoveredItem property. --- Dalamud/Game/Internal/Gui/GameGui.cs | 36 +++++++++++++++++++ .../Internal/Gui/GameGuiAddressResolver.cs | 4 ++- 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/Dalamud/Game/Internal/Gui/GameGui.cs b/Dalamud/Game/Internal/Gui/GameGui.cs index 6444c0374..86de67e7a 100644 --- a/Dalamud/Game/Internal/Gui/GameGui.cs +++ b/Dalamud/Game/Internal/Gui/GameGui.cs @@ -18,6 +18,10 @@ namespace Dalamud.Game.Internal.Gui { private delegate IntPtr HandleItemHoverDelegate(IntPtr hoverState, IntPtr a2, IntPtr a3, ulong a4); private readonly Hook handleItemHoverHook; + [UnmanagedFunctionPointer(CallingConvention.ThisCall)] + private delegate IntPtr HandleItemOutDelegate(IntPtr hoverState, IntPtr a2, IntPtr a3, ulong a4); + private readonly Hook handleItemOutHook; + /// /// The item ID that is currently hovered by the player. 0 when no item is hovered. /// If > 1.000.000, subtract 1.000.000 and treat it as HQ @@ -38,6 +42,7 @@ namespace Dalamud.Game.Internal.Gui { Log.Verbose("GameGuiManager address {Address}", Address.BaseAddress); Log.Verbose("SetGlobalBgm address {Address}", Address.SetGlobalBgm); Log.Verbose("HandleItemHover address {Address}", Address.HandleItemHover); + Log.Verbose("HandleItemOut address {Address}", Address.HandleItemOut); Chat = new ChatGui(Address.ChatManager, scanner, dalamud); @@ -49,6 +54,11 @@ namespace Dalamud.Game.Internal.Gui { new Hook(Address.HandleItemHover, new HandleItemHoverDelegate(HandleItemHoverDetour), this); + + this.handleItemOutHook = + new Hook(Address.HandleItemOut, + new HandleItemOutDelegate(HandleItemOutDetour), + this); } private IntPtr HandleSetGlobalBgmDetour(UInt16 bgmKey, byte a2, UInt32 a3, UInt32 a4, UInt32 a5, byte a6) { @@ -64,6 +74,7 @@ namespace Dalamud.Game.Internal.Gui { if (retVal.ToInt64() == 22) { var itemId = (ulong)Marshal.ReadInt32(hoverState, 0x130); + this.HoveredItem = itemId; try { HoveredItemChanged?.Invoke(this, itemId); @@ -77,18 +88,43 @@ namespace Dalamud.Game.Internal.Gui { return retVal; } + private IntPtr HandleItemOutDetour(IntPtr hoverState, IntPtr a2, IntPtr a3, ulong a4) + { + var retVal = this.handleItemOutHook.Original(hoverState, a2, a3, a4); + + if (a3 != IntPtr.Zero && a4 == 1) { + var a3Val = Marshal.ReadByte(a3, 0x8); + + if (a3Val == 255) { + this.HoveredItem = 0ul; + + try { + HoveredItemChanged?.Invoke(this, 0ul); + } catch (Exception e) { + Log.Error(e, "Could not dispatch HoveredItemChanged event."); + } + + Log.Verbose("HoverItemId: 0"); + } + } + + return retVal; + } + public void SetBgm(ushort bgmKey) => this.setGlobalBgmHook.Original(bgmKey, 0, 0, 0, 0, 0); public void Enable() { Chat.Enable(); this.setGlobalBgmHook.Enable(); this.handleItemHoverHook.Enable(); + this.handleItemOutHook.Enable(); } public void Dispose() { Chat.Dispose(); this.setGlobalBgmHook.Dispose(); this.handleItemHoverHook.Dispose(); + this.handleItemOutHook.Dispose(); } } } diff --git a/Dalamud/Game/Internal/Gui/GameGuiAddressResolver.cs b/Dalamud/Game/Internal/Gui/GameGuiAddressResolver.cs index 091543c56..8fbda8a5a 100644 --- a/Dalamud/Game/Internal/Gui/GameGuiAddressResolver.cs +++ b/Dalamud/Game/Internal/Gui/GameGuiAddressResolver.cs @@ -10,7 +10,8 @@ namespace Dalamud.Game.Internal.Gui { public IntPtr SetGlobalBgm { get; private set; } public IntPtr HandleItemHover { get; set; } - + public IntPtr HandleItemOut { get; set; } + public GameGuiAddressResolver(IntPtr baseAddress) { BaseAddress = baseAddress; } @@ -27,6 +28,7 @@ namespace Dalamud.Game.Internal.Gui { protected override void Setup64Bit(SigScanner sig) { SetGlobalBgm = sig.ScanText("4C 8B 15 ?? ?? ?? ?? 4D 85 D2 74 58"); HandleItemHover = sig.ScanText("E8 ?? ?? ?? ?? 48 8B 5C 24 ?? 48 89 AE ?? ?? ?? ??"); + HandleItemOut = sig.ScanText("48 89 5C 24 ?? 57 48 83 EC 20 48 8B FA 48 8B D9 4D"); } } }