Files
HellionChat/ipc.md
T
JonKazama-Hellion 76a4de1192 docs(ipc): align IPC integration guide with HellionChat.* channel names
ipc.md guides third-party plugin authors who want to bind to our
context-menu IPC and our typing-state IPC. After the v1.0.0 channel
rename (ChatTwo.* → HellionChat.*) the example code in this file no
longer matched the channels the plugin actually exposes — third-party
authors who copy-pasted from the doc would see silent no-op subscriptions.

Updated:
- All 6 channel string literals in code samples (Register, Unregister,
  Invoke, Available, GetChatInputState, ChatInputStateChanged)
- Code-path references in the Typing State IPC explanation block
  (HellionChat.Code.ChatType, HellionChat/Configuration.cs etc.)
- Class/variable name in the example (ChatTwoIpc → HellionChatIpc)
- Prose references to the plugin name

Added a short migration note at the top so existing integrators see
the rename in one paragraph instead of having to diff the file.
2026-05-03 22:29:07 +02:00

6.2 KiB
Executable File

Context Menu IPC Integration

If you want to display custom menu items in the chat context menu, you can use Hellion Chat's IPC.

Migrating from Chat 2: the channel-name prefix changed from ChatTwo.* to HellionChat.* in v1.0.0. If you previously bound to ChatTwo.Register etc., rename to HellionChat.Register etc. Tuple shapes and call semantics are unchanged.

Here's an example.

public class ContextMenuIntegration {
    // This is used to register your plugin with the IPC. It will return an ID
    // that you should save for later.
    private ICallGateSubscriber<string> Register { get; }
    // This is used to unregister your plugin from the IPC. You should call this
    // when your plugin is unloaded.
    private ICallGateSubscriber<string, object?> Unregister { get; }
    // You should subscribe to this event in order to receive a notification
    // when Hellion Chat is loaded or updated, so you can re-register.
    private ICallGateSubscriber<object?> Available { get; }
    // Subscribe to this to draw your custom context menu items.
    private ICallGateSubscriber<string, PlayerPayload?, ulong, Payload?, SeString?, SeString?, object?> Invoke { get; }

    // The registration ID.
    private string? _id;

    public HellionChatIpc(DalamudPluginInterface @interface) {
        this.Register = @interface.GetIpcSubscriber<string>("HellionChat.Register");
        this.Unregister = @interface.GetIpcSubscriber<string, object?>("HellionChat.Unregister");
        this.Invoke = @interface.GetIpcSubscriber<string, PlayerPayload?, ulong, Payload?, SeString?, SeString?, object?>("HellionChat.Invoke");
        this.Available = @interface.GetIpcSubscriber<object?>("HellionChat.Available");
    }

    public void Enable() {
        // When Hellion Chat becomes available (if it loads after this plugin) or
        // when Hellion Chat is updated, register automatically.
        this.Available.Subscribe(() => this.Register());
        // Register if Hellion Chat is already loaded.
        this.Register();

        // Listen for context menu events.
        this.Invoke.Subscribe(this.Integration);
    }

    private void Register() {
        // Register and save the registration ID.
        this._id = this.Register.InvokeFunc();
    }

    public void Disable() {
        if (this._id != null) {
            this.Unregister.InvokeAction(this._id);
            this._id = null;
        }

        this.Invoke.Unsubscribe(this.Integration);
    }

    private void Integration(string id, PlayerPayload? sender, ulong contentId, Payload? payload, SeString? senderString, SeString? content) {
        // Make sure the ID is the same as the saved registration ID.
        if (id != this._id) {
            return;
        }

        // Draw your custom menu items here.
        // sender is the first PlayerPayload contained in the sender SeString
        // contentId is the content ID of the message sender or 0 if not known
        // payload is the payload that was right-clicked, if any (excluding text)
        // senderString is the message sender SeString
        // content is the message content SeString
        if (ImGui.Selectable("Test plugin")) {
            PluginLog.Log($"hi!\nsender: {sender}\ncontent id: {contentId:X}\npayload: {payload}\nsender string: {senderString}\ncontent string: {content}");
        }
    }
}

Typing State IPC

If you need to know whether the player is currently interacting with Hellion Chat's input box, subscribe to the typing IPC.

  • HellionChat.GetChatInputState: call this function to retrieve the current state.
  • HellionChat.ChatInputStateChanged: subscribe to this event to receive updates whenever the state changes (and once immediately after subscribing). Both IPC endpoints use the same tuple payload:
(bool InputVisible, bool InputFocused, bool HasText, bool IsTyping, int TextLength, ChatType ChannelType)
  • InputVisible: true when Hellion Chat is not hidden by user/cutscene/battle settings.
  • InputFocused: true while the Hellion Chat input box currently has keyboard focus.
  • HasText: true when the input buffer contains more than whitespace.
  • IsTyping: convenience flag (InputFocused && HasText).
  • TextLength: length of the raw input buffer.
  • ChannelType: the HellionChat.Code.ChatType representing the channel/mode that will be used if the buffer is submitted. This value comes from the current tab's UsedChannel (HellionChat/Configuration.cs) which the plugin keeps in sync by hooking the in-game shell (HellionChat/GameFunctions/Chat.cs) and by resolving temporary overrides inside the chat UI (HellionChat/Ui/ChatLogWindow.cs:597). InputChannel values are converted into the exported ChatType via HellionChat/Code/InputChannelExt.ToChatType. Example usage:
public sealed class TypingIntegration {
    private ICallGateSubscriber<(bool InputVisible, bool InputFocused, bool HasText, bool IsTyping, int TextLength, ChatType ChannelType)> GetChatInputState { get; }
    private ICallGateSubscriber<(bool InputVisible, bool InputFocused, bool HasText, bool IsTyping, int TextLength, ChatType ChannelType)> ChatInputStateChanged { get; }
    public TypingIntegration(DalamudPluginInterface @interface) {
        this.GetChatInputState = @interface.GetIpcSubscriber<(bool, bool, bool, bool, int, ChatType)>("HellionChat.GetChatInputState");
        this.ChatInputStateChanged = @interface.GetIpcSubscriber<(bool, bool, bool, bool, int, ChatType)>("HellionChat.ChatInputStateChanged");
    }
    public void Enable() {
        this.ChatInputStateChanged.Subscribe(OnChatInputStateChanged);
        // Optionally poll the current state on enable.
        var state = this.GetChatInputState.InvokeFunc();
        PluginLog.Information($"Initial typing state: {state}");
    }
    public void Disable() {
        this.ChatInputStateChanged.Unsubscribe(OnChatInputStateChanged);
    }

    private void OnChatInputStateChanged((bool InputVisible, bool InputFocused, bool HasText, bool IsTyping, int TextLength, ChatType ChannelType) state) {
        if (state.IsTyping) {
            // Show typing indicator.
        } else {
            // Hide typing indicator.
        }
    }
}

All integrations are called inside of an ImGui BeginMenu.