diff --git a/Dalamud/Game/Addon/Lifecycle/AddonArgTypes/AddonFocusChangedArgs.cs b/Dalamud/Game/Addon/Lifecycle/AddonArgTypes/AddonFocusChangedArgs.cs new file mode 100644 index 000000000..8936a233b --- /dev/null +++ b/Dalamud/Game/Addon/Lifecycle/AddonArgTypes/AddonFocusChangedArgs.cs @@ -0,0 +1,22 @@ +namespace Dalamud.Game.Addon.Lifecycle.AddonArgTypes; + +/// +/// Addon argument data for OnFocusChanged events. +/// +public class AddonFocusChangedArgs : AddonArgs +{ + /// + /// Initializes a new instance of the class. + /// + internal AddonFocusChangedArgs() + { + } + + /// + public override AddonArgsType Type => AddonArgsType.FocusChanged; + + /// + /// Gets or sets a value indicating whether the window is being focused or unfocused. + /// + public bool ShouldFocus { get; set; } +} diff --git a/Dalamud/Game/Addon/Lifecycle/AddonArgsType.cs b/Dalamud/Game/Addon/Lifecycle/AddonArgsType.cs index 46ee479ac..bc48eeed0 100644 --- a/Dalamud/Game/Addon/Lifecycle/AddonArgsType.cs +++ b/Dalamud/Game/Addon/Lifecycle/AddonArgsType.cs @@ -44,4 +44,9 @@ public enum AddonArgsType /// Contains argument data for Close. /// Close, + + /// + /// Contains argument data for OnFocusChanged. + /// + FocusChanged, } diff --git a/Dalamud/Game/Addon/Lifecycle/AddonEvent.cs b/Dalamud/Game/Addon/Lifecycle/AddonEvent.cs index 3b9c6e867..74c84d754 100644 --- a/Dalamud/Game/Addon/Lifecycle/AddonEvent.cs +++ b/Dalamud/Game/Addon/Lifecycle/AddonEvent.cs @@ -203,4 +203,14 @@ public enum AddonEvent /// Be aware this is only called for certain popup windows, it is not triggered when clicking on windows. /// PostFocus, + + /// + /// An event that is fired before an addon processes its FocusChanged method. + /// + PreFocusChanged, + + /// + /// An event that is fired after a addon processes its FocusChanged method. + /// + PostFocusChanged, } diff --git a/Dalamud/Game/Addon/Lifecycle/AddonVirtualTable.cs b/Dalamud/Game/Addon/Lifecycle/AddonVirtualTable.cs index 736415738..1b2c828f8 100644 --- a/Dalamud/Game/Addon/Lifecycle/AddonVirtualTable.cs +++ b/Dalamud/Game/Addon/Lifecycle/AddonVirtualTable.cs @@ -42,6 +42,7 @@ internal unsafe class AddonVirtualTable : IDisposable private readonly AddonArgs onMouseOverArgs = new(); private readonly AddonArgs onMouseOutArgs = new(); private readonly AddonArgs focusArgs = new(); + private readonly AddonFocusChangedArgs focusChangedArgs = new(); private readonly AtkUnitBase* atkUnitBase; @@ -63,6 +64,7 @@ internal unsafe class AddonVirtualTable : IDisposable private readonly AtkUnitBase.Delegates.OnMouseOver onMouseOverFunction; private readonly AtkUnitBase.Delegates.OnMouseOut onMouseOutFunction; private readonly AtkUnitBase.Delegates.Focus focusFunction; + private readonly AtkUnitBase.Delegates.OnFocusChange onFocusChangeFunction; /// /// Initializes a new instance of the class. @@ -103,6 +105,7 @@ internal unsafe class AddonVirtualTable : IDisposable this.onMouseOverFunction = this.OnAddonMouseOver; this.onMouseOutFunction = this.OnAddonMouseOut; this.focusFunction = this.OnAddonFocus; + this.onFocusChangeFunction = this.OnAddonFocusChange; // Overwrite specific virtual table entries this.ModifiedVirtualTable->Dtor = (delegate* unmanaged)Marshal.GetFunctionPointerForDelegate(this.destructorFunction); @@ -121,6 +124,7 @@ internal unsafe class AddonVirtualTable : IDisposable this.ModifiedVirtualTable->OnMouseOver = (delegate* unmanaged)Marshal.GetFunctionPointerForDelegate(this.onMouseOverFunction); this.ModifiedVirtualTable->OnMouseOut = (delegate* unmanaged)Marshal.GetFunctionPointerForDelegate(this.onMouseOutFunction); this.ModifiedVirtualTable->Focus = (delegate* unmanaged)Marshal.GetFunctionPointerForDelegate(this.focusFunction); + this.ModifiedVirtualTable->OnFocusChange = (delegate* unmanaged)Marshal.GetFunctionPointerForDelegate(this.onFocusChangeFunction); } /// @@ -630,6 +634,36 @@ internal unsafe class AddonVirtualTable : IDisposable } } + private void OnAddonFocusChange(AtkUnitBase* thisPtr, bool isFocused) + { + try + { + this.LogEvent(EnableLogging); + + this.focusChangedArgs.Addon = thisPtr; + this.focusChangedArgs.ShouldFocus = isFocused; + + this.lifecycleService.InvokeListenersSafely(AddonEvent.PreFocusChanged, this.focusChangedArgs); + + isFocused = this.focusChangedArgs.ShouldFocus; + + try + { + this.OriginalVirtualTable->OnFocusChange(thisPtr, isFocused); + } + catch (Exception e) + { + Log.Error(e, "Caught exception when calling original Addon OnFocusChanged. This may be a bug in the game or another plugin hooking this method."); + } + + this.lifecycleService.InvokeListenersSafely(AddonEvent.PostFocusChanged, this.focusChangedArgs); + } + catch (Exception e) + { + Log.Error(e, "Caught exception from Dalamud when attempting to process OnAddonFocusChange."); + } + } + [Conditional("DEBUG")] private void LogEvent(bool loggingEnabled, [CallerMemberName] string caller = "") {