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>
private const int MenuActionsOffset = 0x428;
private const int ActorIdOffset = 0xEF0;
private const int ContentIdLowerOffset = 0xEE0;
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 delegate IntPtr GetAddonByInternalIdDelegate(IntPtr raptureAtkUnitManager, short id);
@ -47,9 +55,9 @@ namespace XivCommon.Functions {
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);
@ -97,7 +105,7 @@ namespace XivCommon.Functions {
}
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();
}
}
@ -166,7 +174,7 @@ namespace XivCommon.Functions {
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);
if (addonName == null) {
goto Original;
@ -183,9 +191,13 @@ namespace XivCommon.Functions {
goto Original;
}
var agent = this.GetContextMenuAgent();
var actorId = *(uint*) (agent + ActorIdOffset);
var contentIdLower = *(uint*) (agent + ContentIdLowerOffset);
var item = registered[idx];
try {
item.Action();
item.Action(addon, agent, new ContextMenuItemSelectedArgs(actorId, contentIdLower));
} catch (Exception ex) {
PluginLog.LogError(ex, "Exception in custom context menu item");
}
@ -264,14 +276,14 @@ namespace XivCommon.Functions {
/// <summary>
/// The action to perform when this item is clicked.
/// </summary>
public Action Action { get; }
public ContextMenu.ContextMenuItemSelectedDelegate Action { get; }
/// <summary>
/// Create a new context menu item.
/// </summary>
/// <param name="name">the English name of the item, copied to other languages</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.NameJapanese = name;
this.NameFrench = name;
@ -280,4 +292,24 @@ namespace XivCommon.Functions {
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;
}
}
}