From e94ded628adcfcbd12f207eb6443b00482e02e6e Mon Sep 17 00:00:00 2001 From: Loskh <1020612624@qq.com> Date: Mon, 5 Jan 2026 22:42:04 +0800 Subject: [PATCH] fix: respect system dark mode setting --- .../Interface/Internal/InterfaceManager.cs | 43 ++++++++++++++++++- .../Windows/Settings/Tabs/SettingsTabLook.cs | 9 +++- Dalamud/Memory/MemoryHelper.cs | 25 +++++++++++ 3 files changed, 75 insertions(+), 2 deletions(-) diff --git a/Dalamud/Interface/Internal/InterfaceManager.cs b/Dalamud/Interface/Internal/InterfaceManager.cs index 96fcb7dfd..72a9eb0f2 100644 --- a/Dalamud/Interface/Internal/InterfaceManager.cs +++ b/Dalamud/Interface/Internal/InterfaceManager.cs @@ -32,6 +32,7 @@ using Dalamud.Interface.Windowing; using Dalamud.Interface.Windowing.Persistence; using Dalamud.IoC.Internal; using Dalamud.Logging.Internal; +using Dalamud.Memory; using Dalamud.Plugin.Services; using Dalamud.Utility; using Dalamud.Utility.Timing; @@ -500,6 +501,34 @@ internal partial class InterfaceManager : IInternalDisposableService ImGuiHelpers.ClearStacksOnContext(); } + /// + /// Applies immersive dark mode to the game window based on the current system theme setting. + /// + internal void SetImmersiveModeFromSystemTheme() + { + bool useDark = this.IsSystemInDarkMode(); + this.SetImmersiveMode(useDark); + } + + /// + /// Checks whether the system use dark mode. + /// + /// Returns true if dark mode is preferred. + internal bool IsSystemInDarkMode() + { + try + { + using var key = Microsoft.Win32.Registry.CurrentUser.OpenSubKey( + @"Software\Microsoft\Windows\CurrentVersion\Themes\Personalize"); + var value = key?.GetValue("AppsUseLightTheme") as int?; + return value != 1; + } + catch + { + return false; + } + } + /// /// Toggle Windows 11 immersive mode on the game window. /// @@ -744,6 +773,18 @@ internal partial class InterfaceManager : IInternalDisposableService private void WndProcHookManagerOnPreWndProc(WndProcEventArgs args) { + if (args.Message == WM.WM_SETTINGCHANGE) + { + if (this.dalamudConfiguration.WindowIsImmersive) + { + if (MemoryHelper.EqualsZeroTerminatedWideString("ImmersiveColorSet", args.LParam) || + MemoryHelper.EqualsZeroTerminatedWideString("VisualStyleChanged", args.LParam)) + { + this.SetImmersiveModeFromSystemTheme(); + } + } + } + var r = this.backend?.ProcessWndProcW(args.Hwnd, args.Message, args.WParam, args.LParam); if (r is not null) args.SuppressWithValue(r.Value); @@ -858,7 +899,7 @@ internal partial class InterfaceManager : IInternalDisposableService { // Requires that game window to be there, which will be the case once game swap chain is initialized. if (Service.Get().WindowIsImmersive) - this.SetImmersiveMode(true); + this.SetImmersiveModeFromSystemTheme(); } catch (Exception ex) { diff --git a/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabLook.cs b/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabLook.cs index 9b2c418b6..3bb16ca74 100644 --- a/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabLook.cs +++ b/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabLook.cs @@ -65,7 +65,14 @@ internal sealed class SettingsTabLook : SettingsTab { try { - Service.GetNullable()?.SetImmersiveMode(b); + if (b) + { + Service.GetNullable()?.SetImmersiveModeFromSystemTheme(); + } + else + { + Service.GetNullable()?.SetImmersiveMode(false); + } } catch (Exception ex) { diff --git a/Dalamud/Memory/MemoryHelper.cs b/Dalamud/Memory/MemoryHelper.cs index 2eae1be6d..f0f4c991f 100644 --- a/Dalamud/Memory/MemoryHelper.cs +++ b/Dalamud/Memory/MemoryHelper.cs @@ -264,6 +264,31 @@ public static unsafe class MemoryHelper } } + /// + /// Compares a UTF-16 character span with a null-terminated UTF-16 string at . + /// + /// UTF-16 character span (e.g., from a string literal). + /// Address of null-terminated UTF-16 (wide) string, as used by Windows APIs. + /// if equal; otherwise, . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe bool EqualsZeroTerminatedWideString( + scoped ReadOnlySpan charSpan, + nint memoryAddress) + { + if (memoryAddress == 0) + return charSpan.Length == 0; + + char* p = (char*)memoryAddress; + + foreach (char c in charSpan) + { + if (*p++ != c) + return false; + } + + return *p == '\0'; + } + /// /// Read a UTF-8 encoded string from a specified memory address. ///