feat: add context for context menu

This commit is contained in:
Anna 2021-04-27 11:24:39 -04:00
parent 82414d294b
commit a7a3ca3e29
Signed by: anna
GPG Key ID: 0B391D8F06FCD9E0

View File

@ -37,8 +37,16 @@ namespace XivCommon.Functions {
/// </summary> /// </summary>
private const int MenuActionsOffset = 0x428; private const int MenuActionsOffset = 0x428;
private const int ActorIdOffset = 0xEF0;
private const int ContentIdLowerOffset = 0xEE0;
private const int NoopContextId = 0x67; private const int NoopContextId = 0x67;
/// <summary>
/// The delegate that is run when a context menu item is selected.
/// </summary>
public delegate void ContextMenuItemSelectedDelegate(IntPtr addon, IntPtr agent, ContextMenuItemSelectedArgs args);
private unsafe delegate byte ContextMenuOpenDelegate(IntPtr addon, int menuSize, AtkValue* atkValueArgs); private unsafe delegate byte ContextMenuOpenDelegate(IntPtr addon, int menuSize, AtkValue* atkValueArgs);
private delegate IntPtr GetAddonByInternalIdDelegate(IntPtr raptureAtkUnitManager, short id); private delegate IntPtr GetAddonByInternalIdDelegate(IntPtr raptureAtkUnitManager, short id);
@ -47,9 +55,9 @@ namespace XivCommon.Functions {
private Hook<ContextMenuOpenDelegate>? ContextMenuOpenHook { get; } private Hook<ContextMenuOpenDelegate>? ContextMenuOpenHook { get; }
private delegate byte ContextMenuItemSelectedDelegate(IntPtr addon, int index, byte a3); private delegate byte ContextMenuItemSelectedInternalDelegate(IntPtr addon, int index, byte a3);
private Hook<ContextMenuItemSelectedDelegate>? ContextMenuItemSelectedHook { get; } private Hook<ContextMenuItemSelectedInternalDelegate>? ContextMenuItemSelectedHook { get; }
private unsafe delegate void AtkValueChangeTypeDelegate(AtkValue* thisPtr, ValueType type); private unsafe delegate void AtkValueChangeTypeDelegate(AtkValue* thisPtr, ValueType type);
@ -97,7 +105,7 @@ namespace XivCommon.Functions {
} }
if (scanner.TryScanText(Signatures.ContextMenuSelected, out var selectedPtr, "Context Menu selected")) { if (scanner.TryScanText(Signatures.ContextMenuSelected, out var selectedPtr, "Context Menu selected")) {
this.ContextMenuItemSelectedHook = new Hook<ContextMenuItemSelectedDelegate>(selectedPtr, new ContextMenuItemSelectedDelegate(this.ItemSelectedDetour)); this.ContextMenuItemSelectedHook = new Hook<ContextMenuItemSelectedInternalDelegate>(selectedPtr, new ContextMenuItemSelectedInternalDelegate(this.ItemSelectedDetour));
this.ContextMenuItemSelectedHook.Enable(); this.ContextMenuItemSelectedHook.Enable();
} }
} }
@ -166,7 +174,7 @@ namespace XivCommon.Functions {
return this.ContextMenuOpenHook!.Original(addon, menuSize, atkValueArgs); return this.ContextMenuOpenHook!.Original(addon, menuSize, atkValueArgs);
} }
private byte ItemSelectedDetour(IntPtr addon, int index, byte a3) { private unsafe byte ItemSelectedDetour(IntPtr addon, int index, byte a3) {
var addonName = this.GetParentAddonName(addon); var addonName = this.GetParentAddonName(addon);
if (addonName == null) { if (addonName == null) {
goto Original; goto Original;
@ -183,9 +191,13 @@ namespace XivCommon.Functions {
goto Original; goto Original;
} }
var agent = this.GetContextMenuAgent();
var actorId = *(uint*) (agent + ActorIdOffset);
var contentIdLower = *(uint*) (agent + ContentIdLowerOffset);
var item = registered[idx]; var item = registered[idx];
try { try {
item.Action(); item.Action(addon, agent, new ContextMenuItemSelectedArgs(actorId, contentIdLower));
} catch (Exception ex) { } catch (Exception ex) {
PluginLog.LogError(ex, "Exception in custom context menu item"); PluginLog.LogError(ex, "Exception in custom context menu item");
} }
@ -264,14 +276,14 @@ namespace XivCommon.Functions {
/// <summary> /// <summary>
/// The action to perform when this item is clicked. /// The action to perform when this item is clicked.
/// </summary> /// </summary>
public Action Action { get; } public ContextMenu.ContextMenuItemSelectedDelegate Action { get; }
/// <summary> /// <summary>
/// Create a new context menu item. /// Create a new context menu item.
/// </summary> /// </summary>
/// <param name="name">the English name of the item, copied to other languages</param> /// <param name="name">the English name of the item, copied to other languages</param>
/// <param name="action">the action to perform on click</param> /// <param name="action">the action to perform on click</param>
public ContextMenuItem(string name, Action action) { public ContextMenuItem(string name, ContextMenu.ContextMenuItemSelectedDelegate action) {
this.NameEnglish = name; this.NameEnglish = name;
this.NameJapanese = name; this.NameJapanese = name;
this.NameFrench = name; this.NameFrench = name;
@ -280,4 +292,24 @@ namespace XivCommon.Functions {
this.Action = action; this.Action = action;
} }
} }
/// <summary>
/// Arguments for the context menu item selected delegate.
/// </summary>
public class ContextMenuItemSelectedArgs {
/// <summary>
/// The actor ID for this context menu. May be invalid (0xE0000000).
/// </summary>
public uint ActorId { get; }
/// <summary>
/// The lower half of the content ID of the actor for this context menu. May be zero.
/// </summary>
public uint ContentIdLower { get; }
internal ContextMenuItemSelectedArgs(uint actorId, uint contentIdLower) {
this.ContentIdLower = contentIdLower;
this.ActorId = actorId;
}
}
} }