From a243443a7d4aff63e721185ed09983e1395e9e7a Mon Sep 17 00:00:00 2001 From: Wang Haoyu Date: Sat, 9 May 2026 22:35:54 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E7=B3=BB=E7=BB=9F?= =?UTF-8?q?=E5=BC=BA=E8=B0=83=E8=89=B2=E8=A1=8C=E5=8A=A8=E5=B9=B6=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E5=AA=92=E4=BD=93=E8=A7=84=E5=88=99=E4=B8=8E=E4=B8=BB?= =?UTF-8?q?=E9=A2=98=E5=90=8C=E6=AD=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Actions/SwitchSystemAccentColorAction.cs | 53 ++++++++++++++++++++ Controls/AccentColorSettingsControl.cs | 34 +++++++++++++ Plugin.cs | 32 ++++++++---- Services/AdaptiveThemeSyncService.cs | 31 +++++++++--- Settings/AccentColorSettings.cs | 8 +++ SettingsPage/SystemToolsSettingsViewModel.cs | 1 + 6 files changed, 141 insertions(+), 18 deletions(-) create mode 100644 Actions/SwitchSystemAccentColorAction.cs create mode 100644 Controls/AccentColorSettingsControl.cs create mode 100644 Settings/AccentColorSettings.cs diff --git a/Actions/SwitchSystemAccentColorAction.cs b/Actions/SwitchSystemAccentColorAction.cs new file mode 100644 index 0000000..96bffeb --- /dev/null +++ b/Actions/SwitchSystemAccentColorAction.cs @@ -0,0 +1,53 @@ +using ClassIsland.Core.Abstractions.Automation; +using ClassIsland.Core.Attributes; +using Microsoft.Extensions.Logging; +using Microsoft.Win32; +using System; +using System.Globalization; +using System.Threading.Tasks; +using SystemTools.Settings; + +namespace SystemTools.Actions; + +[ActionInfo("SystemTools.SwitchSystemAccentColor", "切换系统强调色", "\uE790", false)] +public class SwitchSystemAccentColorAction(ILogger logger) : ActionBase +{ + private readonly ILogger _logger = logger; + + protected override async Task OnInvoke() + { + if (Settings == null || string.IsNullOrWhiteSpace(Settings.ColorHex)) return; + + try + { + var color = ParseColor(Settings.ColorHex); + var dword = ((uint)color.A << 24) | ((uint)color.R << 16) | ((uint)color.G << 8) | color.B; + + using var dwmKey = Registry.CurrentUser.CreateSubKey(@"Software\Microsoft\Windows\DWM"); + dwmKey?.SetValue("AccentColor", dword, RegistryValueKind.DWord); + dwmKey?.SetValue("ColorPrevalence", 1, RegistryValueKind.DWord); + + using var explorerKey = Registry.CurrentUser.CreateSubKey(@"Software\Microsoft\Windows\CurrentVersion\Explorer\Accent"); + explorerKey?.SetValue("AccentColorMenu", dword, RegistryValueKind.DWord); + + _logger.LogInformation("系统强调色已切换为 {Color}", Settings.ColorHex); + } + catch (Exception ex) + { + _logger.LogError(ex, "切换系统强调色失败"); + throw; + } + + await base.OnInvoke(); + } + + private static (byte A, byte R, byte G, byte B) ParseColor(string colorHex) + { + var hex = colorHex.Trim().TrimStart('#'); + if (hex.Length == 6) hex = "FF" + hex; + if (hex.Length != 8) throw new FormatException("颜色格式无效"); + + var value = uint.Parse(hex, NumberStyles.HexNumber, CultureInfo.InvariantCulture); + return ((byte)(value >> 24), (byte)(value >> 16), (byte)(value >> 8), (byte)value); + } +} diff --git a/Controls/AccentColorSettingsControl.cs b/Controls/AccentColorSettingsControl.cs new file mode 100644 index 0000000..c1b5bd0 --- /dev/null +++ b/Controls/AccentColorSettingsControl.cs @@ -0,0 +1,34 @@ +using Avalonia.Controls; +using Avalonia.Layout; +using ClassIsland.Core.Abstractions.Controls; +using SystemTools.Settings; + +namespace SystemTools.Controls; + +public class AccentColorSettingsControl : ActionSettingsControlBase +{ + private readonly ColorPicker _colorPicker; + + public AccentColorSettingsControl() + { + var panel = new StackPanel { Spacing = 10, Margin = new(10) }; + panel.Children.Add(new TextBlock { Text = "切换系统强调色", FontSize = 14, FontWeight = Avalonia.Media.FontWeight.Bold }); + + _colorPicker = new ColorPicker + { + IsAlphaEnabled = false, + HorizontalAlignment = HorizontalAlignment.Left + }; + _colorPicker.ColorChanged += (_, _) => Settings.ColorHex = _colorPicker.Color.ToString(); + + panel.Children.Add(_colorPicker); + Content = panel; + } + + protected override void OnInitialized() + { + base.OnInitialized(); + if (Avalonia.Media.Color.TryParse(Settings.ColorHex, out var color)) + _colorPicker.Color = color; + } +} diff --git a/Plugin.cs b/Plugin.cs index 58ac528..c4aabc8 100644 --- a/Plugin.cs +++ b/Plugin.cs @@ -258,6 +258,7 @@ private void RegisterBaseActions(IServiceCollection services) RegisterActionIfEnabled(services, config, "SystemTools.ChangeWallpaper"); RegisterActionIfEnabled(services, config, "SystemTools.SwitchTheme"); + RegisterActionIfEnabled(services, config, "SystemTools.SwitchSystemAccentColor"); // 实用工具 RegisterActionIfEnabled(services, config, @@ -625,6 +626,9 @@ private static bool HandleInTimePeriodRule(object? settings) return current >= start || current <= end; } + private static DateTime _lastMediaRuleCheckAt = DateTime.MinValue; + private static bool _lastMediaRuleResult; + private static bool HandleMediaMusicPlayingRule(object? settings) { if (!OperatingSystem.IsWindowsVersionAtLeast(10, 0, 17134)) @@ -632,28 +636,32 @@ private static bool HandleMediaMusicPlayingRule(object? settings) return false; } + var now = DateTime.UtcNow; + if (now - _lastMediaRuleCheckAt < TimeSpan.FromMilliseconds(800)) + { + return _lastMediaRuleResult; + } + try { var manager = WinMedia.GlobalSystemMediaTransportControlsSessionManager.RequestAsync() .AsTask().GetAwaiter().GetResult(); - if (manager == null) - return false; - - var sessions = manager.GetSessions(); - if (sessions == null || sessions.Count == 0) - return false; - - return sessions.Any(session => + var sessions = manager?.GetSessions(); + var isPlaying = sessions != null && sessions.Any(session => { var playbackInfo = session.GetPlaybackInfo(); - return playbackInfo != null && - playbackInfo.PlaybackStatus == WinMedia.GlobalSystemMediaTransportControlsSessionPlaybackStatus.Playing; + return playbackInfo?.PlaybackStatus == WinMedia.GlobalSystemMediaTransportControlsSessionPlaybackStatus.Playing; }); + + _lastMediaRuleResult = isPlaying; + _lastMediaRuleCheckAt = now; + return isPlaying; } catch { - return false; + _lastMediaRuleCheckAt = now; + return _lastMediaRuleResult; } } @@ -768,6 +776,8 @@ private void BuildPersonalizationMenu(MainConfigData config) items.Add(new ActionMenuTreeItem("SystemTools.ChangeWallpaper", "切换壁纸", "\uE9BC")); if (config.IsActionEnabled("SystemTools.SwitchTheme")) items.Add(new ActionMenuTreeItem("SystemTools.SwitchTheme", "切换主题色", "\uF42F")); + if (config.IsActionEnabled("SystemTools.SwitchSystemAccentColor")) + items.Add(new ActionMenuTreeItem("SystemTools.SwitchSystemAccentColor", "切换系统强调色", "\uE790")); if (items.Count > 0) { diff --git a/Services/AdaptiveThemeSyncService.cs b/Services/AdaptiveThemeSyncService.cs index e8f55fa..33dc6b1 100644 --- a/Services/AdaptiveThemeSyncService.cs +++ b/Services/AdaptiveThemeSyncService.cs @@ -1,6 +1,7 @@ using Avalonia.Threading; using ClassIsland.Core; using ClassIsland.Core.Abstractions.Services; +using System.Reflection; using Microsoft.Extensions.Logging; using System; using System.Drawing; @@ -56,13 +57,7 @@ private void OnTick(object? sender, EventArgs e) return; } - var themeService = IAppHost.TryGetService(); - if (themeService == null) - { - return; - } - - themeService.SetTheme(targetTheme.Value, null); + ApplyThemeLikeAppSettings(targetTheme.Value); _lastAppliedTheme = targetTheme; _logger.LogDebug("已自动匹配主题为:{Theme}", targetTheme == 1 ? "黑暗" : "明亮"); } @@ -178,6 +173,28 @@ private static bool ResolveUseTopAreaFromClassIslandSettings() return null; } + private static void ApplyThemeLikeAppSettings(int targetTheme) + { + var settingsServiceObj = IAppHost.TryGetService(); + if (settingsServiceObj != null) + { + var type = settingsServiceObj.GetType(); + if (type.Name == "SettingsService") + { + var settingsProp = type.GetProperty("Settings", BindingFlags.Instance | BindingFlags.Public); + var settings = settingsProp?.GetValue(settingsServiceObj); + var themeProp = settings?.GetType().GetProperty("Theme", BindingFlags.Instance | BindingFlags.Public); + if (themeProp?.CanWrite == true) + { + themeProp.SetValue(settings, targetTheme); + return; + } + } + } + + IAppHost.TryGetService()?.SetTheme(targetTheme, null); + } + private static string[] GetPossibleClassIslandSettingsPaths() { var localAppData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); diff --git a/Settings/AccentColorSettings.cs b/Settings/AccentColorSettings.cs new file mode 100644 index 0000000..df075ef --- /dev/null +++ b/Settings/AccentColorSettings.cs @@ -0,0 +1,8 @@ +using System.Text.Json.Serialization; + +namespace SystemTools.Settings; + +public class AccentColorSettings +{ + [JsonPropertyName("colorHex")] public string ColorHex { get; set; } = "#FF0078D4"; +} diff --git a/SettingsPage/SystemToolsSettingsViewModel.cs b/SettingsPage/SystemToolsSettingsViewModel.cs index 8d480a7..511a9d7 100644 --- a/SettingsPage/SystemToolsSettingsViewModel.cs +++ b/SettingsPage/SystemToolsSettingsViewModel.cs @@ -195,6 +195,7 @@ public void InitializeFeatureItems() ("SystemTools.Delete", "删除", "文件操作"), ("SystemTools.ChangeWallpaper", "切换壁纸", "系统个性化"), ("SystemTools.SwitchTheme", "切换主题色", "系统个性化"), + ("SystemTools.SwitchSystemAccentColor", "切换系统强调色", "系统个性化"), ("SystemTools.FullscreenClock", "沉浸式时钟", "其他工具"), ("SystemTools.KillProcess", "退出进程", "实用工具"), ("SystemTools.ScreenShot", "屏幕截图", "实用工具"), From 588cec70da10318e5e28bddaedf762db4e965517 Mon Sep 17 00:00:00 2001 From: Wang Haoyu Date: Sun, 10 May 2026 13:30:32 +0800 Subject: [PATCH 2/3] =?UTF-8?q?=E6=9B=B4=E6=96=B0=20SwitchSystemAccentColo?= =?UTF-8?q?rAction.cs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Actions/SwitchSystemAccentColorAction.cs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/Actions/SwitchSystemAccentColorAction.cs b/Actions/SwitchSystemAccentColorAction.cs index 96bffeb..9b7f327 100644 --- a/Actions/SwitchSystemAccentColorAction.cs +++ b/Actions/SwitchSystemAccentColorAction.cs @@ -4,6 +4,7 @@ using Microsoft.Win32; using System; using System.Globalization; +using System.Runtime.InteropServices; using System.Threading.Tasks; using SystemTools.Settings; @@ -14,6 +15,13 @@ public class SwitchSystemAccentColorAction(ILogger _logger = logger; + [DllImport("user32.dll", SetLastError = true)] + static extern IntPtr SendMessageTimeout(IntPtr hWnd, uint Msg, UIntPtr wParam, string lParam, uint fuFlags, uint uTimeout, out UIntPtr lpdwResult); + + const uint HWND_BROADCAST = 0xFFFF; + const uint WM_SETTINGCHANGE = 0x001A; + const uint SMTO_ABORTIFHUNG = 0x0002; + protected override async Task OnInvoke() { if (Settings == null || string.IsNullOrWhiteSpace(Settings.ColorHex)) return; @@ -21,15 +29,23 @@ protected override async Task OnInvoke() try { var color = ParseColor(Settings.ColorHex); - var dword = ((uint)color.A << 24) | ((uint)color.R << 16) | ((uint)color.G << 8) | color.B; + // Windows 使用 ABGR 格式(低位字节是 R) + var dword = ((uint)color.A << 24) | ((uint)color.B << 16) | ((uint)color.G << 8) | color.R; + // ColorizationColor 通常使用 C4 (196) 作为 Alpha + var colorizationDword = (0xC4u << 24) | ((uint)color.B << 16) | ((uint)color.G << 8) | color.R; using var dwmKey = Registry.CurrentUser.CreateSubKey(@"Software\Microsoft\Windows\DWM"); dwmKey?.SetValue("AccentColor", dword, RegistryValueKind.DWord); + dwmKey?.SetValue("ColorizationColor", colorizationDword, RegistryValueKind.DWord); + dwmKey?.SetValue("ColorizationAfterglow", colorizationDword, RegistryValueKind.DWord); dwmKey?.SetValue("ColorPrevalence", 1, RegistryValueKind.DWord); using var explorerKey = Registry.CurrentUser.CreateSubKey(@"Software\Microsoft\Windows\CurrentVersion\Explorer\Accent"); explorerKey?.SetValue("AccentColorMenu", dword, RegistryValueKind.DWord); + // 通知 Windows 刷新主题色 + SendMessageTimeout((IntPtr)HWND_BROADCAST, WM_SETTINGCHANGE, (UIntPtr)0, "ImmersiveColorSet", SMTO_ABORTIFHUNG, 5000, out _); + _logger.LogInformation("系统强调色已切换为 {Color}", Settings.ColorHex); } catch (Exception ex) From 48cba437fd3b6549657794596262fe2645dfaef2 Mon Sep 17 00:00:00 2001 From: Wang Haoyu Date: Sun, 10 May 2026 21:08:28 +0800 Subject: [PATCH 3/3] =?UTF-8?q?=E6=9B=B4=E6=96=B0=20Plugin.cs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Plugin.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Plugin.cs b/Plugin.cs index c4aabc8..a7e177f 100644 --- a/Plugin.cs +++ b/Plugin.cs @@ -492,7 +492,7 @@ private void BuildBaseActionTree() } // 系统个性化 - if (HasAnyActionEnabled(config, "SystemTools.ChangeWallpaper", "SystemTools.SwitchTheme")) + if (HasAnyActionEnabled(config, "SystemTools.ChangeWallpaper", "SystemTools.SwitchTheme", "SystemTools.SwitchSystemAccentColor")) { IActionService.ActionMenuTree["SystemTools 行动"].Add(new ActionMenuTreeGroup("系统个性化…", "\uF42F")); BuildPersonalizationMenu(config);