diff --git a/Dalamud/Dalamud.csproj b/Dalamud/Dalamud.csproj index 76e84e779..a02780438 100644 --- a/Dalamud/Dalamud.csproj +++ b/Dalamud/Dalamud.csproj @@ -68,7 +68,7 @@ - + all diff --git a/Dalamud/Interface/ImGuiBackend/InputHandler/Win32InputHandler.cs b/Dalamud/Interface/ImGuiBackend/InputHandler/Win32InputHandler.cs index 1842028e2..b3316abca 100644 --- a/Dalamud/Interface/ImGuiBackend/InputHandler/Win32InputHandler.cs +++ b/Dalamud/Interface/ImGuiBackend/InputHandler/Win32InputHandler.cs @@ -245,6 +245,9 @@ internal sealed unsafe partial class Win32InputHandler : IImGuiInputHandler return default(LRESULT); } + if (ImGui.IsAnyItemActive()) + ImGui.ClearWindowFocus(); + break; } @@ -531,7 +534,7 @@ internal sealed unsafe partial class Win32InputHandler : IImGuiInputHandler // We still want to return MA_NOACTIVATE // https://docs.microsoft.com/en-us/windows/win32/inputdev/wm-mouseactivate - return 0x3; + return MA.MA_NOACTIVATE; case WM.WM_NCHITTEST: // Let mouse pass-through the window. This will allow the backend to set io.MouseHoveredViewport properly (which is OPTIONAL). // The ImGuiViewportFlags_NoInputs flag is set while dragging a viewport, as want to detect the window behind the one we are dragging. @@ -539,8 +542,7 @@ internal sealed unsafe partial class Win32InputHandler : IImGuiInputHandler // your main loop after calling UpdatePlatformWindows(). Iterate all viewports/platform windows and pass the flag to your windowing system. if (viewport.Flags.HasFlag(ImGuiViewportFlags.NoInputs)) { - // https://docs.microsoft.com/en-us/windows/win32/inputdev/wm-nchittest - return -1; + return HTTRANSPARENT; } break; diff --git a/Dalamud/Interface/Internal/DalamudInterface.cs b/Dalamud/Interface/Internal/DalamudInterface.cs index d475d36bc..70645fdde 100644 --- a/Dalamud/Interface/Internal/DalamudInterface.cs +++ b/Dalamud/Interface/Internal/DalamudInterface.cs @@ -575,16 +575,6 @@ internal class DalamudInterface : IInternalDisposableService if (this.isCreditsDarkening) this.DrawCreditsDarkeningAnimation(); - - // Release focus of any ImGui window if we click into the game. - var io = ImGui.GetIO(); - if (!io.WantCaptureMouse && (global::Windows.Win32.PInvoke.GetKeyState((int)VirtualKey.LBUTTON) & 0x8000) != 0) - { - unsafe - { - ImGui.SetWindowFocus((byte*)null); - } - } } catch (Exception ex) { diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/SeStringRendererTestWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/SeStringRendererTestWidget.cs index 7ff5a63be..b39cf258c 100644 --- a/Dalamud/Interface/Internal/Windows/Data/Widgets/SeStringRendererTestWidget.cs +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/SeStringRendererTestWidget.cs @@ -226,7 +226,7 @@ internal unsafe class SeStringRendererTestWidget : IDataWindowWidget { this.testStringBuffer.Dispose(); this.testStringBuffer = ImVectorWrapper.CreateFromSpan( - "\n\nLorem ipsum dolor sit amet, conse<->ctetur adipi<->scing elit. Maece<->nas digni<->ssim sem at inter<->dum ferme<->ntum. Praes<->ent ferme<->ntum conva<->llis velit sit amet hendr<->erit. Sed eu nibh magna. Integ<->er nec lacus in velit porta euism<->od sed et lacus. Sed non mauri<->s venen<->atis, matti<->s metus in, aliqu<->et dolor. Aliqu<->am erat volut<->pat. Nulla venen<->atis velit ac susci<->pit euism<->od. suspe<->ndisse maxim<->us viver<->ra dui id dapib<->us. Nam torto<->r dolor, eleme<->ntum quis orci id, pulvi<->nar fring<->illa quam. Pelle<->ntesque laore<->et viver<->ra torto<->r eget matti<->s. Vesti<->bulum eget porta ante, a molli<->s nulla. Curab<->itur a ligul<->a leo. Aliqu<->am volut<->pat sagit<->tis dapib<->us.\n\nFusce iacul<->is aliqu<->am mi, eget portt<->itor arcu solli<->citudin conse<->ctetur. suspe<->ndisse aliqu<->am commo<->do tinci<->dunt. Duis sed posue<->re tellu<->s. Sed phare<->tra ex vel torto<->r pelle<->ntesque, inter<->dum porta sapie<->n digni<->ssim. Queue Dun Scait<->h. Cras aliqu<->et at nulla quis moles<->tie. Vesti<->bulum eu ligul<->a sapie<->n. Curab<->itur digni<->ssim feugi<->at volut<->pat.\n\nVesti<->bulum condi<->mentum laore<->et rhonc<->us. Vivam<->us et accum<->san purus. Curab<->itur inter<->dum vel ligul<->a ac euism<->od. Donec sed nisl digni<->ssim est tinci<->dunt iacul<->is. Praes<->ent hendr<->erit pelle<->ntesque nisl, quis lacin<->ia arcu dictu<->m sit amet. Aliqu<->am variu<->s lectu<->s vel mauri<->s imper<->diet posue<->re. Ut gravi<->da non sapie<->n sed hendr<->erit.\n\nProin quis dapib<->us odio. Cras sagit<->tis non sem sed porta. Donec iacul<->is est ligul<->a, digni<->ssim aliqu<->et augue matti<->s vitae. Duis ullam<->corper tempu<->s odio, non vesti<->bulum est biben<->dum quis. In purus elit, vehic<->ula tinci<->dunt dictu<->m in, aucto<->r nec enim. Curab<->itur a nisi in leo matti<->s pelle<->ntesque id nec sem. Nunc vel ultri<->ces nisl. Nam congu<->e vulpu<->tate males<->uada. Aenea<->n vesti<->bulum mauri<->s leo, sit amet iacul<->is est imper<->diet ut. Phase<->llus nec lobor<->tis lacus, sit amet scele<->risque purus. Nam id lacin<->ia velit, euism<->od feugi<->at dui. Nulla sodal<->es odio ligul<->a, et hendr<->erit torto<->r maxim<->us eu. Donec et sem eu magna volut<->pat accum<->san non ut lectu<->s.\n\nVivam<->us susci<->pit ferme<->ntum gravi<->da. Cras nec conse<->ctetur magna. Vivam<->us ante massa, accum<->san sit amet felis et, tempu<->s iacul<->is ipsum. Pelle<->ntesque vitae nisi accum<->san, venen<->atis lectu<->s aucto<->r, aliqu<->et liber<->o. Nam nec imper<->diet justo. Vivam<->us ut vehic<->ula turpi<->s. Nunc lobor<->tis pelle<->ntesque urna, sit amet solli<->citudin nibh fauci<->bus in. Curab<->itur eu lobor<->tis lacus. Donec eu hendr<->erit diam, vitae cursu<->s odio. Cras eget scele<->risque mi.\n\n· Testing aaaaalink aaaaabbbb.\n· Open example.com\n· Open example.org\n\n\n\ncolortype502,edgecolortype503\n\nOpacity values are ignored:\nopacity FF\nopacity 80\nopacity 00\nTest 1\nTest 2\nWithout edgeShadowWith edge"u8, + "\n\nLorem ipsum dolor sit amet, conse<->ctetur adipi<->scing elit. Maece<->nas digni<->ssim sem at inter<->dum ferme<->ntum. Praes<->ent ferme<->ntum conva<->llis velit sit amet hendr<->erit. Sed eu nibh magna. Integ<->er nec lacus in velit porta euism<->od sed et lacus. Sed non mauri<->s venen<->atis, matti<->s metus in, aliqu<->et dolor. Aliqu<->am erat volut<->pat. Nulla venen<->atis velit ac susci<->pit euism<->od. suspe<->ndisse maxim<->us viver<->ra dui id dapib<->us. Nam torto<->r dolor, eleme<->ntum quis orci id, pulvi<->nar fring<->illa quam. Pelle<->ntesque laore<->et viver<->ra torto<->r eget matti<->s. Vesti<->bulum eget porta ante, a molli<->s nulla. Curab<->itur a ligul<->a leo. Aliqu<->am volut<->pat sagit<->tis dapib<->us.\n\nFusce iacul<->is aliqu<->am mi, eget portt<->itor arcu solli<->citudin conse<->ctetur. suspe<->ndisse aliqu<->am commo<->do tinci<->dunt. Duis sed posue<->re tellu<->s. Sed phare<->tra ex vel torto<->r pelle<->ntesque, inter<->dum porta sapie<->n digni<->ssim. Queue Dun Scait<->h. Cras aliqu<->et at nulla quis moles<->tie. Vesti<->bulum eu ligul<->a sapie<->n. Curab<->itur digni<->ssim feugi<->at volut<->pat.\n\nVesti<->bulum condi<->mentum laore<->et rhonc<->us. Vivam<->us et accum<->san purus. Curab<->itur inter<->dum vel ligul<->a ac euism<->od. Donec sed nisl digni<->ssim est tinci<->dunt iacul<->is. Praes<->ent hendr<->erit pelle<->ntesque nisl, quis lacin<->ia arcu dictu<->m sit amet. Aliqu<->am variu<->s lectu<->s vel mauri<->s imper<->diet posue<->re. Ut gravi<->da non sapie<->n sed hendr<->erit.\n\nProin quis dapib<->us odio. Cras sagit<->tis non sem sed porta. Donec iacul<->is est ligul<->a, digni<->ssim aliqu<->et augue matti<->s vitae. Duis ullam<->corper tempu<->s odio, non vesti<->bulum est biben<->dum quis. In purus elit, vehic<->ula tinci<->dunt dictu<->m in, aucto<->r nec enim. Curab<->itur a nisi in leo matti<->s pelle<->ntesque id nec sem. Nunc vel ultri<->ces nisl. Nam congu<->e vulpu<->tate males<->uada. Aenea<->n vesti<->bulum mauri<->s leo, sit amet iacul<->is est imper<->diet ut. Phase<->llus nec lobor<->tis lacus, sit amet scele<->risque purus. Nam id lacin<->ia velit, euism<->od feugi<->at dui. Nulla sodal<->es odio ligul<->a, et hendr<->erit torto<->r maxim<->us eu. Donec et sem eu magna volut<->pat accum<->san non ut lectu<->s.\n\nVivam<->us susci<->pit ferme<->ntum gravi<->da. Cras nec conse<->ctetur magna. Vivam<->us ante massa, accum<->san sit amet felis et, tempu<->s iacul<->is ipsum. Pelle<->ntesque vitae nisi accum<->san, venen<->atis lectu<->s aucto<->r, aliqu<->et liber<->o. Nam nec imper<->diet justo. Vivam<->us ut vehic<->ula turpi<->s. Nunc lobor<->tis pelle<->ntesque urna, sit amet solli<->citudin nibh fauci<->bus in. Curab<->itur eu lobor<->tis lacus. Donec eu hendr<->erit diam, vitae cursu<->s odio. Cras eget scele<->risque mi.\n\n· Testing aaaaalink aaaaabbbb.\n· Open example.com\n· Open example.org\n\n\n\ncolortype502,edgecolortype503\n\nOpacity values are ignored:\nopacity FF\nopacity 80\nopacity 00\nTest 1\nTest 2\nWithout edgeShadowWith edge"u8, minCapacity: 65536); this.testString = string.Empty; } diff --git a/Dalamud/Utility/Util.cs b/Dalamud/Utility/Util.cs index a95f3ed66..a1c2eb6b2 100644 --- a/Dalamud/Utility/Util.cs +++ b/Dalamud/Utility/Util.cs @@ -9,6 +9,7 @@ using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; +using System.Threading; using System.Threading.Tasks; using Dalamud.Bindings.ImGui; @@ -27,6 +28,8 @@ using Windows.Win32.System.Memory; using Windows.Win32.System.Ole; using Windows.Win32.UI.WindowsAndMessaging; +using Dalamud.Interface.Internal; + using FLASHWINFO = Windows.Win32.UI.WindowsAndMessaging.FLASHWINFO; using HWND = Windows.Win32.Foundation.HWND; using MEMORY_BASIC_INFORMATION = Windows.Win32.System.Memory.MEMORY_BASIC_INFORMATION; @@ -522,17 +525,36 @@ public static partial class Util public static bool IsWindows11() => Environment.OSVersion.Version.Build >= 22000; /// - /// Open a link in the default browser. + /// Open a link in the default browser, and attempts to focus the newly launched application. /// /// The link to open. - public static void OpenLink(string url) - { - var process = new ProcessStartInfo(url) + public static void OpenLink(string url) => new Thread( + static url => { - UseShellExecute = true, - }; - Process.Start(process); - } + try + { + var psi = new ProcessStartInfo((string)url!) + { + UseShellExecute = true, + ErrorDialogParentHandle = Service.GetNullable() is { } im + ? im.GameWindowHandle + : 0, + Verb = "open", + }; + if (Process.Start(psi) is not { } process) + return; + + if (process.Id != 0) + TerraFX.Interop.Windows.Windows.AllowSetForegroundWindow((uint)process.Id); + process.WaitForInputIdle(); + TerraFX.Interop.Windows.Windows.SetForegroundWindow( + (TerraFX.Interop.Windows.HWND)process.MainWindowHandle); + } + catch (Exception e) + { + Log.Error(e, "{fn}: failed to open {url}", nameof(OpenLink), url); + } + }).Start(url); /// /// Perform a "zipper merge" (A, 1, B, 2, C, 3) of multiple enumerables, allowing for lists to end early. diff --git a/imgui/Dalamud.Bindings.ImGui/Custom/ImGui.Widgets.cs b/imgui/Dalamud.Bindings.ImGui/Custom/ImGui.Widgets.cs index 7ff8bf272..9cbc3dc9a 100644 --- a/imgui/Dalamud.Bindings.ImGui/Custom/ImGui.Widgets.cs +++ b/imgui/Dalamud.Bindings.ImGui/Custom/ImGui.Widgets.cs @@ -564,8 +564,12 @@ public static unsafe partial class ImGui name.Dispose(); } + /// Sets the current window to be focused / top-most. + /// Prefer using . public static void SetWindowFocus() => ImGuiNative.SetWindowFocus(); + /// Sets a named window to be focused / top-most. + /// Name of the window to focus. Use default to remove focus. public static void SetWindowFocus(ImU8String name) { fixed (byte* namePtr = &name.GetPinnableNullTerminatedReference()) @@ -573,6 +577,9 @@ public static unsafe partial class ImGui name.Dispose(); } + /// Removes focus from any window. + public static void ClearWindowFocus() => ImGuiNative.SetWindowFocus(null); + public static void SetWindowPos(Vector2 pos, ImGuiCond cond = ImGuiCond.None) => ImGuiNative.SetWindowPos(pos, cond); diff --git a/imgui/Dalamud.Bindings.ImGui/ImU8String.cs b/imgui/Dalamud.Bindings.ImGui/ImU8String.cs index 63ccbfb28..88858ca10 100644 --- a/imgui/Dalamud.Bindings.ImGui/ImU8String.cs +++ b/imgui/Dalamud.Bindings.ImGui/ImU8String.cs @@ -35,7 +35,7 @@ public ref struct ImU8String : IDisposable } public ImU8String(int literalLength, int formattedCount) - : this(ReadOnlySpan.Empty) + : this(""u8) { this.state |= State.Interpolation; literalLength += formattedCount * 4; @@ -51,6 +51,12 @@ public ref struct ImU8String : IDisposable public ImU8String(ReadOnlySpan text, bool ensureNullTermination = false) : this() { + if (Unsafe.IsNullRef(in MemoryMarshal.GetReference(text))) + { + this.state = State.None; + return; + } + this.state = State.Initialized; if (text.IsEmpty) { @@ -82,6 +88,12 @@ public ref struct ImU8String : IDisposable public ImU8String(ReadOnlySpan text) : this() { + if (Unsafe.IsNullRef(in MemoryMarshal.GetReference(text))) + { + this.state = State.None; + return; + } + this.state = State.Initialized | State.NullTerminated; this.Length = Encoding.UTF8.GetByteCount(text); if (this.Length + 1 < AllocFreeBufferSize) @@ -313,6 +325,12 @@ public ref struct ImU8String : IDisposable FixAlignment(startingPos, alignment); } + public void AppendFormatted(object? value) => this.AppendFormatted(value!); + public void AppendFormatted(object? value, string? format) => this.AppendFormatted(value!, format); + public void AppendFormatted(object? value, int alignment) => this.AppendFormatted(value!, alignment); + public void AppendFormatted(object? value, int alignment, string? format) => + this.AppendFormatted(value!, alignment, format); + public void AppendFormatted(T value) => this.AppendFormatted(value, null); public void AppendFormatted(T value, string? format)