# 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. ```cs 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 Register { get; } // This is used to unregister your plugin from the IPC. You should call this // when your plugin is unloaded. private ICallGateSubscriber 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 Available { get; } // Subscribe to this to draw your custom context menu items. private ICallGateSubscriber Invoke { get; } // The registration ID. private string? _id; public HellionChatIpc(DalamudPluginInterface @interface) { this.Register = @interface.GetIpcSubscriber("HellionChat.Register"); this.Unregister = @interface.GetIpcSubscriber("HellionChat.Unregister"); this.Invoke = @interface.GetIpcSubscriber("HellionChat.Invoke"); this.Available = @interface.GetIpcSubscriber("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: ```cs 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`.