diff --git a/ChatTwo.Tests/ChatTwo.Tests.csproj b/ChatTwo.Tests/ChatTwo.Tests.csproj index 2771b9e..8c20f47 100644 --- a/ChatTwo.Tests/ChatTwo.Tests.csproj +++ b/ChatTwo.Tests/ChatTwo.Tests.csproj @@ -2,7 +2,7 @@ net8.0-windows - + false @@ -17,10 +17,40 @@ - - - ..\..\AppData\Roaming\XIVLauncher\addon\Hooks\dev\Dalamud.dll - - - - \ No newline at end of file + + $(AppData)\XIVLauncher\addon\Hooks\dev + + + + $(DALAMUD_HOME) + + + + $(HOME)/dalamud + + + + + $(DalamudLibPath)\Dalamud.dll + false + + + $(DalamudLibPath)\FFXIVClientStructs.dll + false + + + $(DalamudLibPath)\ImGui.NET.dll + false + + + $(DalamudLibPath)\Lumina.dll + false + + + $(DalamudLibPath)\Lumina.Excel.dll + false + + + + + diff --git a/ChatTwo/Configuration.cs b/ChatTwo/Configuration.cs index 3a697bf..a630c91 100755 --- a/ChatTwo/Configuration.cs +++ b/ChatTwo/Configuration.cs @@ -198,6 +198,9 @@ internal class Tab [NonSerialized] public HashSet TrackedMessageIds = new(); + [NonSerialized] + public InputChannel? PreviousChannel; + ~Tab() { MessagesMutex.Dispose(); } internal bool Contains(Message message) { diff --git a/ChatTwo/GameFunctions/Chat.cs b/ChatTwo/GameFunctions/Chat.cs index 38f7fc7..15b5959 100755 --- a/ChatTwo/GameFunctions/Chat.cs +++ b/ChatTwo/GameFunctions/Chat.cs @@ -162,6 +162,7 @@ internal sealed unsafe class Chat : IDisposable internal bool UsesTellTempChannel { get; set; } internal InputChannel? PreviousChannel { get; private set; } + private bool DirectChat; private long LastRefresh; internal Chat(Plugin plugin) @@ -372,10 +373,10 @@ internal sealed unsafe class Chat : IDisposable if (LastRefresh + 5 * 1000 < Environment.TickCount64) { UpdateKeybinds(); + DirectChat = Plugin.GameConfig.TryGet(UiControlOption.DirectChat, out bool option) && option; LastRefresh = Environment.TickCount64; } - var modifierState = (ModifierFlag) 0; foreach (var modifier in Enum.GetValues()) { @@ -390,6 +391,18 @@ internal sealed unsafe class Chat : IDisposable if (!Keybinds.TryGetValue(toIntercept, out var keybind)) continue; + // Vanilla input has focus, so we ignore Ready Chat and Ready Command keybind + if (toIntercept is "CMD_CHAT" or "CMD_COMMAND") + { + // Vanilla text input has focus + if (RaptureAtkModule.Instance()->AtkModule.IsTextInputActive()) + continue; + + // Direct chat option is selected + if (DirectChat) + continue; + } + void Intercept(VirtualKey key, ModifierFlag modifier) { if (!Plugin.KeyState.IsVirtualKeyValid(key)) @@ -450,38 +463,32 @@ internal sealed unsafe class Chat : IDisposable if (eventId != 0x31 || value == null || value->UInt is not (0x05 or 0x0C)) return ChatLogRefreshHook!.Original(log, eventId, value); - if (Plugin.GameConfig.TryGet(UiControlOption.DirectChat, out bool option) && option) + if (DirectChat && CurrentCharacter != null) { - if (CurrentCharacter != null) + // FIXME: this whole system sucks + // FIXME v2: I hate everything about this, but it works + Plugin.Framework.RunOnTick(() => { - // FIXME: this whole system sucks - // FIXME v2: I hate everything about this, but it works - Plugin.Framework.RunOnTick(() => + string? input = null; + + var utf8Bytes = MemoryHelper.ReadRaw((nint) CurrentCharacter, 2); + var chars = Encoding.UTF8.GetString(utf8Bytes).ToCharArray(); + if (chars.Length == 0) + return; + + var c = chars[0]; + if (c != '\0' && !char.IsControl(c)) + input = c.ToString(); + + try { - string? input = null; - - var utf8Bytes = MemoryHelper.ReadRaw((nint) CurrentCharacter, 2); - var chars = Encoding.UTF8.GetString(utf8Bytes).ToCharArray(); - if (chars.Length == 0) - return; - - var c = chars[0]; - if (c != '\0' && !char.IsControl(c)) - input = c.ToString(); - - try - { - var args = new ChatActivatedArgs(new ChannelSwitchInfo(null)) { - Input = input, - }; - Activated?.Invoke(args); - } - catch (Exception ex) - { - Plugin.Log.Error(ex, "Error in chat Activated event"); - } - }); - } + Activated?.Invoke(new ChatActivatedArgs(new ChannelSwitchInfo(null)) { Input = input, }); + } + catch (Exception ex) + { + Plugin.Log.Error(ex, "Error in chat Activated event"); + } + }); } string? addIfNotPresent = null; @@ -496,10 +503,7 @@ internal sealed unsafe class Chat : IDisposable try { - var args = new ChatActivatedArgs(new ChannelSwitchInfo(null)) { - AddIfNotPresent = addIfNotPresent, - }; - Activated?.Invoke(args); + Activated?.Invoke(new ChatActivatedArgs(new ChannelSwitchInfo(null)) { AddIfNotPresent = addIfNotPresent, }); } catch (Exception ex) { diff --git a/ChatTwo/Ui/ChatLogWindow.cs b/ChatTwo/Ui/ChatLogWindow.cs index ea015e2..2b43c99 100644 --- a/ChatTwo/Ui/ChatLogWindow.cs +++ b/ChatTwo/Ui/ChatLogWindow.cs @@ -387,6 +387,21 @@ public sealed class ChatLogWindow : Window, IUiComponent } } + private void TabChannelSwitch(Tab tab) + { + // Save the previous channel to restore it later + var current = CurrentTab; + if (current is { Channel: null }) + current.PreviousChannel = Plugin.Functions.Chat.Channel.channel; + + // Channel will be null if PreviousChannel is used + var channel = tab.Channel ?? tab.PreviousChannel; + + // Channel being null it doesn't have a default, and we never selected this channel before + if (channel != null) + SetChannel(tab.Channel ?? tab.PreviousChannel); + } + private bool CutsceneActive => Plugin.Condition[ConditionFlag.OccupiedInCutSceneEvent] || Plugin.Condition[ConditionFlag.WatchingCutscene78]; private bool GposeActive => Plugin.Condition[ConditionFlag.WatchingCutscene]; @@ -1036,12 +1051,11 @@ public sealed class ChatLogWindow : Window, IUiComponent currentTab = tabI; var switchedTab = LastTab != tabI; + if (switchedTab) + TabChannelSwitch(tab); LastTab = tabI; tab.Unread = 0; - if (switchedTab && tab.Channel.HasValue) - SetChannel(tab.Channel.Value); - DrawMessageLog(tab, PayloadHandler, GetRemainingHeightForMessageLog(), switchedTab); ImGui.EndTabItem(); @@ -1083,10 +1097,9 @@ public sealed class ChatLogWindow : Window, IUiComponent currentTab = tabI; switchedTab = LastTab != tabI; + if (switchedTab) + TabChannelSwitch(tab); LastTab = tabI; - - if (switchedTab && tab.Channel.HasValue) - SetChannel(tab.Channel.Value); } }