From 3dae5dba045781eaf94e133be593b21de8238c05 Mon Sep 17 00:00:00 2001 From: shuimo <1743355601@qq.com> Date: Mon, 6 Apr 2026 18:54:57 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E7=A7=BB=E9=99=A4=E6=B3=A2=E7=8E=AF?= =?UTF-8?q?=E5=92=8C=E7=B2=92=E5=AD=90=E6=95=B0=E9=87=8F=E9=99=90=E5=88=B6?= =?UTF-8?q?=EF=BC=8C=E6=B8=85=E7=90=86=E6=97=A0=E7=94=A8=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Web/index.html | 137 +++++++++++++++++++++++++++++++++------------ 1 file changed, 101 insertions(+), 36 deletions(-) diff --git a/src/Web/index.html b/src/Web/index.html index d1a688e..72f2fc0 100644 --- a/src/Web/index.html +++ b/src/Web/index.html @@ -21,7 +21,9 @@ this.opacity = opts.opacity || 1.0; this.speed = opts.speed || 1.0; this.maxTrail = opts.maxTrail || 16; - this.el = opts.el || document.body; + + this.sparkPool = []; + this.wavePool = []; this.waves = []; this.sparks = []; @@ -97,32 +99,63 @@ } boom(x, y) { - this.waves.push({ - x, y, life: 0, max: 18, r: 0, - ring: { - ang: Math.random() * Math.PI * 2, - segs: [ - { off: -0.25 * Math.PI, len: 1.15 * Math.PI }, - { off: 0.00 * Math.PI, len: 1.15 * Math.PI }, - { off: 0.25 * Math.PI, len: 1.15 * Math.PI } - ], - life: 0, maxLife: 30, rs: 0.08 - } - }); + // 优化:使用对象池 + let wave; + if (this.wavePool.length > 0) { + wave = this.wavePool.pop(); + wave.x = x; + wave.y = y; + wave.life = 0; + wave.max = 18; + wave.r = 0; + wave.ring.ang = Math.random() * Math.PI * 2; + wave.ring.life = 0; + } else { + wave = { + x, y, life: 0, max: 18, r: 0, + ring: { + ang: Math.random() * Math.PI * 2, + segs: [ + { off: -0.25 * Math.PI, len: 1.15 * Math.PI }, + { off: 0.00 * Math.PI, len: 1.15 * Math.PI }, + { off: 0.25 * Math.PI, len: 1.15 * Math.PI } + ], + life: 0, maxLife: 30, rs: 0.08 + } + }; + } + this.waves.push(wave); + let particleCount = 4; let speedAdjust = this.scale / 1.5; - for (let i = 0; i < 8; i++) { + for (let i = 0; i < particleCount; i++) { let a = Math.random() * Math.PI * 2; let speed = (4.8 + Math.random() * 2) * speedAdjust; - this.sparks.push({ - x, y, - vx: Math.cos(a) * speed, - vy: Math.sin(a) * speed, - rot: Math.random() * Math.PI * 2, - rs: (Math.random() - 0.5) * 0.28, - s: (4 + Math.random() * 3) * this.scale, - a: 1, f: 0.9 - }); + + let spark; + if (this.sparkPool.length > 0) { + spark = this.sparkPool.pop(); + spark.x = x; + spark.y = y; + spark.vx = Math.cos(a) * speed; + spark.vy = Math.sin(a) * speed; + spark.rot = Math.random() * Math.PI * 2; + spark.rs = (Math.random() - 0.5) * 0.28; + spark.s = (4 + Math.random() * 3) * this.scale; + spark.a = 1; + spark.f = 0.9; + } else { + spark = { + x, y, + vx: Math.cos(a) * speed, + vy: Math.sin(a) * speed, + rot: Math.random() * Math.PI * 2, + rs: (Math.random() - 0.5) * 0.28, + s: (4 + Math.random() * 3) * this.scale, + a: 1, f: 0.9 + }; + } + this.sparks.push(spark); } } @@ -133,6 +166,7 @@ if (this.waves.length > 0 || this.sparks.length > 0 || this.trail.length > 0) { this.ctx.clearRect(0, 0, this.c.width, this.c.height); + // 优化:减少全局合成模式的使用 this.ctx.globalCompositeOperation = "lighter"; for (let i = this.trail.length - 1; i >= 0; i--) { @@ -146,17 +180,44 @@ } if (this.trail.length > 1) { + // this.ctx.beginPath(); + // this.ctx.moveTo(this.trail[0].x, this.trail[0].y); + // for (let i = 1; i < this.trail.length; i++) { + // this.ctx.lineTo(this.trail[i].x, this.trail[i].y); + // } + // this.ctx.lineWidth = 8.0; + + + // this.ctx.strokeStyle = `rgba(${this.color},${this.alpha(0.35)})`; + // this.ctx.stroke(); + + + // =============新增的屎=============== this.ctx.beginPath(); this.ctx.moveTo(this.trail[0].x, this.trail[0].y); for (let i = 1; i < this.trail.length; i++) { this.ctx.lineTo(this.trail[i].x, this.trail[i].y); } - this.ctx.lineWidth = 4.5; - this.ctx.strokeStyle = `rgba(${this.color},${this.alpha(0.35)})`; - this.ctx.shadowBlur = 10; - this.ctx.shadowColor = `rgba(${this.color},${this.alpha(0.45)})`; + this.ctx.lineWidth = 5.0; + + const meteorHead = this.trail[this.trail.length - 1]; + const meteorTail = this.trail[0]; + const gradient = this.ctx.createLinearGradient( + meteorHead.x, meteorHead.y, + meteorTail.x, meteorTail.y + ); + gradient.addColorStop(0, `rgba(${this.color}, 1)`); + gradient.addColorStop(1, `rgba(${this.color}, 0)`); + + this.ctx.shadowColor = `rgba(${this.color}, 0.6)`; + this.ctx.shadowBlur = 3; + this.ctx.shadowOffsetX = 0; + this.ctx.shadowOffsetY = 0; + + this.ctx.strokeStyle = gradient; this.ctx.stroke(); - this.ctx.shadowBlur = 0; + this.ctx.shadowColor = 'transparent'; + } for (let i = this.waves.length - 1; i >= 0; i--) { @@ -170,10 +231,8 @@ this.ctx.beginPath(); this.ctx.arc(w.x, w.y, w.r, 0, Math.PI * 2); this.ctx.fillStyle = `rgba(${this.color},${this.alpha(alpha)})`; - this.ctx.shadowBlur = 10; - this.ctx.shadowColor = `rgba(${this.color},${this.alpha(1)})`; + // 优化:减少阴影效果 this.ctx.fill(); - this.ctx.shadowBlur = 0; } let r = w.ring; @@ -188,12 +247,14 @@ this.ctx.arc(w.x, w.y, w.r + 3 * this.scale, start, start + len); this.ctx.lineWidth = 3.7; this.ctx.strokeStyle = `rgba(245,248,252,${this.alpha(1 - rProg)})`; - this.ctx.shadowBlur = 6; - this.ctx.shadowColor = `rgba(${this.color},${this.alpha(0.75)})`; + // 减少阴影效果 this.ctx.stroke(); - this.ctx.shadowBlur = 0; }); - if (progress >= 1 && rProg >= 1) this.waves.splice(i, 1); + if (progress >= 1 && rProg >= 1) { + // 回收对象到对象池 + this.wavePool.push(this.waves[i]); + this.waves.splice(i, 1); + } } for (let i = this.sparks.length - 1; i >= 0; i--) { @@ -204,7 +265,11 @@ s.vy *= Math.pow(s.f, frameScale); s.rot += s.rs * frameScale; s.a -= 0.032 * frameScale; - if (s.a <= 0) { this.sparks.splice(i, 1); continue; } + if (s.a <= 0) { + this.sparkPool.push(this.sparks[i]); + this.sparks.splice(i, 1); + continue; + } this.ctx.save(); this.ctx.translate(s.x, s.y); From b82bda8f48fa56f6e8700d7f1e31d3ecb4e1753c Mon Sep 17 00:00:00 2001 From: shuimo <1743355601@qq.com> Date: Tue, 7 Apr 2026 16:10:43 +0800 Subject: [PATCH 2/3] test --- .vscode/launch.json | 26 ++++++++++++++++++++++++++ .vscode/tasks.json | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+) create mode 100644 .vscode/launch.json create mode 100644 .vscode/tasks.json diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..a37c1c8 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,26 @@ +{ + "version": "0.2.0", + "configurations": [ + { + // 使用 IntelliSense 找出 C# 调试存在哪些属性 + // 将悬停用于现有属性的说明 + // 有关详细信息,请访问 https://github.com/dotnet/vscode-csharp/blob/main/debugger-launchjson.md + "name": ".NET Core Launch (console)", + "type": "coreclr", + "request": "launch", + "preLaunchTask": "build", + // 如果已更改目标框架,请确保更新程序路径。 + "program": "${workspaceFolder}/src/bin/Debug/net8.0-windows10.0.19041.0/BASpark.dll", + "args": [], + "cwd": "${workspaceFolder}/src", + // 有关“控制台”字段的详细信息,请参阅 https://aka.ms/VSCode-CS-LaunchJson-Console + "console": "internalConsole", + "stopAtEntry": false + }, + { + "name": ".NET Core Attach", + "type": "coreclr", + "request": "attach" + } + ] +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..3eb040e --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,41 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "build", + "command": "dotnet", + "type": "process", + "args": [ + "build", + "${workspaceFolder}/src/BASpark.csproj", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary;ForceNoAlign" + ], + "problemMatcher": "$msCompile" + }, + { + "label": "publish", + "command": "dotnet", + "type": "process", + "args": [ + "publish", + "${workspaceFolder}/src/BASpark.csproj", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary;ForceNoAlign" + ], + "problemMatcher": "$msCompile" + }, + { + "label": "watch", + "command": "dotnet", + "type": "process", + "args": [ + "watch", + "run", + "--project", + "${workspaceFolder}/src/BASpark.csproj" + ], + "problemMatcher": "$msCompile" + } + ] +} \ No newline at end of file From 379398146a0eebbd30094d4d7783b0d1976dd616 Mon Sep 17 00:00:00 2001 From: shuimo <1743355601@qq.com> Date: Sun, 17 May 2026 13:33:38 +0800 Subject: [PATCH 3/3] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E4=BA=86=E8=87=AA?= =?UTF-8?q?=E5=AE=9A=E4=B9=89html=E7=9A=84=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BASpark.csproj | 6 ++ src/ConfigManager.cs | 80 ++++++++++++++++++ src/ControlPanelWindow.xaml | 16 +++- src/ControlPanelWindow.xaml.cs | 82 ++++++++++++++++++ src/MainWindow.xaml.cs | 95 ++++++++++++++++----- src/OverlayManager.cs | 22 ++++- src/Resources/Strings.en.resx | 24 ++++++ src/Resources/Strings.ja.resx | 24 ++++++ src/Resources/Strings.resx | 24 ++++++ src/UiLocalizer.cs | 4 + src/Web/custom-effect-template.html | 107 ++++++++++++++++++++++++ src/Web/custom-effect-test.html | 125 ++++++++++++++++++++++++++++ 12 files changed, 587 insertions(+), 22 deletions(-) create mode 100644 src/Web/custom-effect-template.html create mode 100644 src/Web/custom-effect-test.html diff --git a/src/BASpark.csproj b/src/BASpark.csproj index a0d39c7..45cb207 100644 --- a/src/BASpark.csproj +++ b/src/BASpark.csproj @@ -35,5 +35,11 @@ + + + PreserveNewest + + + \ No newline at end of file diff --git a/src/ConfigManager.cs b/src/ConfigManager.cs index e32cc3b..e928597 100644 --- a/src/ConfigManager.cs +++ b/src/ConfigManager.cs @@ -1,7 +1,9 @@ using Microsoft.Win32; using System; using System.Collections.Generic; +using System.IO; using System.Linq; +using System.Reflection; namespace BASpark { @@ -51,8 +53,11 @@ public class ScreenSelectionState public static class ConfigManager { private const string RegPath = @"Software\BASpark"; + public const string CustomHtmlVirtualHost = "baspark.custom"; + public const string CustomHtmlTemplateFileName = "custom-effect-template.html"; public static string ParticleColor { get; set; } = "45,175,255"; + public static string CustomHtmlPath { get; set; } = ""; public static bool IsEffectEnabled { get; set; } = true; public static bool AutoStart { get; set; } = false; public static bool AgreedToPrivacy { get; set; } = false; @@ -122,6 +127,7 @@ public static void Load() ScreenSelections = key.GetValue("ScreenSelections", "")?.ToString() ?? ""; UiLanguage = key.GetValue("UiLanguage", "")?.ToString() ?? ""; ScrollbarVisibility = ParseScrollbarVisibility(key.GetValue("ScrollbarVisibility", "OnScroll")?.ToString()); + CustomHtmlPath = key.GetValue("CustomHtmlPath", "")?.ToString() ?? ""; if (!string.IsNullOrWhiteSpace(UiLanguage)) { Localization.ApplyCulture(UiLanguage); @@ -199,6 +205,80 @@ public static void GetAnimationSpeedsForOverlay(out double trailSpeed, out doubl } } + public static bool IsUsingCustomHtml => TryResolveCustomHtmlUri(out _, out _); + + public static bool TryResolveCustomHtmlUri(out string navigateUri, out string folderPath) + { + navigateUri = string.Empty; + folderPath = string.Empty; + if (string.IsNullOrWhiteSpace(CustomHtmlPath)) + { + return false; + } + + string fullPath; + try + { + fullPath = Path.GetFullPath(CustomHtmlPath.Trim()); + } + catch + { + return false; + } + + if (!File.Exists(fullPath)) + { + return false; + } + + string ext = Path.GetExtension(fullPath); + if (!ext.Equals(".html", StringComparison.OrdinalIgnoreCase) && + !ext.Equals(".htm", StringComparison.OrdinalIgnoreCase)) + { + return false; + } + + folderPath = Path.GetDirectoryName(fullPath) ?? string.Empty; + if (string.IsNullOrEmpty(folderPath)) + { + return false; + } + + string fileName = Path.GetFileName(fullPath); + navigateUri = $"https://{CustomHtmlVirtualHost}/{Uri.EscapeDataString(fileName)}"; + return true; + } + + public static string? GetWebSamplesDirectory() + { + static bool IsWebSamplesDir(string path) => + Directory.Exists(path) && + File.Exists(Path.Combine(path, CustomHtmlTemplateFileName)); + + string besideExe = Path.Combine(AppContext.BaseDirectory, "Web"); + if (IsWebSamplesDir(besideExe)) + { + return besideExe; + } + + string? dir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); + for (int i = 0; i < 8 && !string.IsNullOrEmpty(dir); i++) + { + foreach (string relative in new[] { "Web", Path.Combine("src", "Web") }) + { + string candidate = Path.Combine(dir, relative); + if (IsWebSamplesDir(candidate)) + { + return candidate; + } + } + + dir = Path.GetDirectoryName(dir); + } + + return null; + } + public static List GetProfiles() => _profiles; public static FilterProfile? GetActiveProfile() diff --git a/src/ControlPanelWindow.xaml b/src/ControlPanelWindow.xaml index 50c9de4..560816f 100644 --- a/src/ControlPanelWindow.xaml +++ b/src/ControlPanelWindow.xaml @@ -376,7 +376,20 @@ - + + + + + + + + + + @@ -493,6 +506,7 @@ + diff --git a/src/ControlPanelWindow.xaml.cs b/src/ControlPanelWindow.xaml.cs index 6132052..24df604 100644 --- a/src/ControlPanelWindow.xaml.cs +++ b/src/ControlPanelWindow.xaml.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.IO; using System.Collections.ObjectModel; using System.Windows; using System.Windows.Controls; @@ -80,6 +81,8 @@ private struct POINT private bool _isCheckingUpdate = false; private bool _suspendLinkedAnimationUiHandlers; private string _languageAtLoad = Localization.CultureZhCn; + private string _customHtmlPathAtLoad = ""; + private string _customHtmlPathPending = ""; public ObservableCollection Profiles { get; set; } = new ObservableCollection(); public ObservableCollection CurrentProfileProcesses { get; set; } = new ObservableCollection(); @@ -105,6 +108,7 @@ public ControlPanelWindow() LoadSettings(); ApplyScrollbarSettings(); UiLocalizer.ApplyControlPanel(this); + UpdateCustomHtmlPathDisplay(); LoadScreenOptions(); CheckAdminStatus(); LoadRemoteNotice(); @@ -522,6 +526,70 @@ private void LoadSettingsCore() { RadioScrollbarOnScroll.IsChecked = true; } + + _customHtmlPathPending = ConfigManager.CustomHtmlPath ?? ""; + _customHtmlPathAtLoad = _customHtmlPathPending; + UpdateCustomHtmlPathDisplay(); + ApplyCustomHtmlUiState(); + } + + private void UpdateCustomHtmlPathDisplay() + { + TxtCustomHtmlPath.Text = string.IsNullOrWhiteSpace(_customHtmlPathPending) + ? Localization.Get("CustomHtml_Builtin") + : _customHtmlPathPending; + } + + private void ApplyCustomHtmlUiState() + { + bool usingCustom = !string.IsNullOrWhiteSpace(_customHtmlPathPending) && + File.Exists(_customHtmlPathPending); + PanelVisualBuiltIn.IsEnabled = !usingCustom; + BtnVisualReset.IsEnabled = !usingCustom; + } + + private void BrowseCustomHtml_Click(object sender, RoutedEventArgs e) + { + var dialog = new Microsoft.Win32.OpenFileDialog + { + Filter = Localization.Get("CustomHtml_FileFilter"), + Title = Localization.Get("CustomHtml_SelectTitle") + }; + + string? webDir = ConfigManager.GetWebSamplesDirectory(); + if (!string.IsNullOrEmpty(webDir)) + { + dialog.InitialDirectory = webDir; + dialog.FileName = ConfigManager.CustomHtmlTemplateFileName; + } + + if (dialog.ShowDialog() == true) + { + if (string.Equals( + Path.GetFileName(dialog.FileName), + "index.html", + StringComparison.OrdinalIgnoreCase)) + { + System.Windows.MessageBox.Show( + this, + Localization.Get("CustomHtml_BuiltinIndexWarning"), + Localization.Get("CustomHtml_SelectTitle"), + MessageBoxButton.OK, + MessageBoxImage.Warning); + return; + } + + _customHtmlPathPending = dialog.FileName; + UpdateCustomHtmlPathDisplay(); + ApplyCustomHtmlUiState(); + } + } + + private void ClearCustomHtml_Click(object sender, RoutedEventArgs e) + { + _customHtmlPathPending = ""; + UpdateCustomHtmlPathDisplay(); + ApplyCustomHtmlUiState(); } private void ApplyScrollbarSettings() @@ -1167,6 +1235,12 @@ private void SaveSettings_Click(object sender, RoutedEventArgs e) ConfigManager.Save("AutoStart", autoStartEnabled); ConfigManager.Save("EnableTelemetry", CheckTelemetry.IsChecked ?? false); ConfigManager.Save("ParticleColor", ConfigManager.ParticleColor); + bool customHtmlPathChanged = !string.Equals( + _customHtmlPathAtLoad, + _customHtmlPathPending, + StringComparison.OrdinalIgnoreCase); + ConfigManager.CustomHtmlPath = _customHtmlPathPending; + ConfigManager.Save("CustomHtmlPath", _customHtmlPathPending); ConfigManager.Save("EffectScale", effectScale); ConfigManager.Save("EffectOpacity", effectOpacity); ConfigManager.Save("UseLinkedAnimationSpeed", useLinkedAnimationSpeed); @@ -1218,6 +1292,13 @@ private void SaveSettings_Click(object sender, RoutedEventArgs e) App.SetAutoStart(ConfigManager.AutoStart); ApplyAutoStartSettings(); + if (customHtmlPathChanged) + { + App.Overlay?.ReloadAllEffectContent(); + _customHtmlPathAtLoad = _customHtmlPathPending; + } + + ApplyCustomHtmlUiState(); App.Overlay?.UpdateColor(ConfigManager.ParticleColor); GetUiAnimationSpeeds(out double overlayTrail, out double overlayClick); App.Overlay?.UpdateEffectSettings(effectScale, effectOpacity, overlayTrail, overlayClick); @@ -1250,6 +1331,7 @@ private void SaveSettings_Click(object sender, RoutedEventArgs e) if (languageChanged) { UiLocalizer.ApplyControlPanel(this); + UpdateCustomHtmlPathDisplay(); LoadScreenOptions(); ConfigManager.Save("LastNoticeContent", string.Empty); LoadRemoteNotice(); diff --git a/src/MainWindow.xaml.cs b/src/MainWindow.xaml.cs index 3e828df..accafba 100644 --- a/src/MainWindow.xaml.cs +++ b/src/MainWindow.xaml.cs @@ -2,6 +2,7 @@ using System.Diagnostics.CodeAnalysis; using System.Drawing; using System.Globalization; +using System.IO; using System.Linq; using System.Runtime.InteropServices; using System.Windows; @@ -193,11 +194,21 @@ private void SafeEnsureTopmost() public void UpdateColor(string color) { + if (ConfigManager.IsUsingCustomHtml) + { + return; + } + ExecuteScript($"if(window.updateColor) window.updateColor('{color}');"); } public void UpdateEffectSettings(double scale, double opacity, double trailSpeed, double clickSpeed) { + if (ConfigManager.IsUsingCustomHtml) + { + return; + } + string scaleStr = scale.ToString("F2", CultureInfo.InvariantCulture); string opacityStr = opacity.ToString("F2", CultureInfo.InvariantCulture); string trailStr = trailSpeed.ToString("F2", CultureInfo.InvariantCulture); @@ -287,25 +298,9 @@ private async System.Threading.Tasks.Task InitWebView() _processFailedHandler = OnWebViewProcessFailed; coreWebView.ProcessFailed += _processFailedHandler; - var streamInfo = System.Windows.Application.GetResourceStream(new Uri("pack://application:,,,/Web/index.html")); - if (streamInfo != null) - { - using var reader = new System.IO.StreamReader(streamInfo.Stream); - string htmlContent = reader.ReadToEnd(); - coreWebView.NavigateToString(htmlContent); - _navigationCompletedHandler = (s, e) => - { - if (_isClosing) return; - - _lastReportedInputMode = null; - _lastReportedAlwaysTrail = null; - UpdateColor(ConfigManager.ParticleColor); - ConfigManager.GetAnimationSpeedsForOverlay(out double trailSp, out double clickSp); - UpdateEffectSettings(ConfigManager.EffectScale, ConfigManager.EffectOpacity, trailSp, clickSp); - SyncInputContext(InputModeMouse); - }; - coreWebView.NavigationCompleted += _navigationCompletedHandler; - } + _navigationCompletedHandler = OnEffectNavigationCompleted; + coreWebView.NavigationCompleted += _navigationCompletedHandler; + LoadEffectContent(coreWebView); } catch (Exception ex) when (IsExpectedWebViewShutdownException(ex)) { @@ -316,6 +311,68 @@ private async System.Threading.Tasks.Task InitWebView() } } + public void ReloadEffectContent() + { + if (!TryGetCoreWebView2(out CoreWebView2? coreWebView)) + { + return; + } + + LoadEffectContent(coreWebView); + } + + private void LoadEffectContent(CoreWebView2 coreWebView) + { + if (ConfigManager.TryResolveCustomHtmlUri(out string navigateUri, out string folderPath)) + { + try + { + coreWebView.SetVirtualHostNameToFolderMapping( + ConfigManager.CustomHtmlVirtualHost, + folderPath, + CoreWebView2HostResourceAccessKind.Allow); + coreWebView.Navigate(navigateUri); + return; + } + catch + { + } + } + + NavigateBuiltinHtml(coreWebView); + } + + private static void NavigateBuiltinHtml(CoreWebView2 coreWebView) + { + var streamInfo = System.Windows.Application.GetResourceStream(new Uri("pack://application:,,,/Web/index.html")); + if (streamInfo == null) + { + return; + } + + using var reader = new StreamReader(streamInfo.Stream); + coreWebView.NavigateToString(reader.ReadToEnd()); + } + + private void OnEffectNavigationCompleted(object? sender, CoreWebView2NavigationCompletedEventArgs e) + { + if (_isClosing || !e.IsSuccess) + { + return; + } + + _lastReportedInputMode = null; + _lastReportedAlwaysTrail = null; + if (!ConfigManager.IsUsingCustomHtml) + { + UpdateColor(ConfigManager.ParticleColor); + ConfigManager.GetAnimationSpeedsForOverlay(out double trailSp, out double clickSp); + UpdateEffectSettings(ConfigManager.EffectScale, ConfigManager.EffectOpacity, trailSp, clickSp); + } + + SyncInputContext(InputModeMouse); + } + private void OnWebViewProcessFailed(object? sender, CoreWebView2ProcessFailedEventArgs e) { if (_isClosing) return; diff --git a/src/OverlayManager.cs b/src/OverlayManager.cs index 0e92050..1073961 100644 --- a/src/OverlayManager.cs +++ b/src/OverlayManager.cs @@ -130,9 +130,27 @@ public void Start() SystemEvents.SessionSwitch += HandleSessionSwitch; } - public void UpdateColor(string color) => ForEachOverlay(w => w.UpdateColor(color)); - public void UpdateEffectSettings(double scale, double opacity, double trailSpeed, double clickSpeed) => + public void UpdateColor(string color) + { + if (ConfigManager.IsUsingCustomHtml) + { + return; + } + + ForEachOverlay(w => w.UpdateColor(color)); + } + + public void UpdateEffectSettings(double scale, double opacity, double trailSpeed, double clickSpeed) + { + if (ConfigManager.IsUsingCustomHtml) + { + return; + } + ForEachOverlay(w => w.UpdateEffectSettings(scale, opacity, trailSpeed, clickSpeed)); + } + + public void ReloadAllEffectContent() => ForEachOverlay(w => w.ReloadEffectContent()); public void UpdateTrailRefreshRate(int hz) { hz = Math.Clamp(hz, 10, 240); diff --git a/src/Resources/Strings.en.resx b/src/Resources/Strings.en.resx index 2821245..77fcacd 100644 --- a/src/Resources/Strings.en.resx +++ b/src/Resources/Strings.en.resx @@ -535,6 +535,30 @@ Download now? Trail refresh rate + + Custom HTML effect + + + Select HTML file + + + Use built-in effect + + + Built-in visual controls below are disabled while a custom HTML file is in use. + + + (Built-in effect) + + + HTML files (*.html;*.htm)|*.html;*.htm + + + Select effect HTML file + + + index.html is the built-in default effect and cannot be used as a custom file. Copy custom-effect-template.html and edit it, or choose your own HTML. + WebView2 initialization failed: {0} diff --git a/src/Resources/Strings.ja.resx b/src/Resources/Strings.ja.resx index c1e935e..3110319 100644 --- a/src/Resources/Strings.ja.resx +++ b/src/Resources/Strings.ja.resx @@ -535,6 +535,30 @@ トレイル更新率 + + カスタム HTML エフェクト + + + HTML ファイルを選択 + + + 組み込みエフェクトに戻す + + + カスタム HTML 使用時は、下の組み込みビジュアル設定は無効になります。 + + + (組み込みエフェクト) + + + HTML ファイル (*.html;*.htm)|*.html;*.htm + + + エフェクト用 HTML を選択 + + + index.html は組み込みの既定エフェクトのため、カスタムファイルとして選べません。custom-effect-template.html をコピーして編集するか、独自の HTML を選んでください。 + WebView2 の初期化に失敗しました: {0} diff --git a/src/Resources/Strings.resx b/src/Resources/Strings.resx index 67d504e..5465852 100644 --- a/src/Resources/Strings.resx +++ b/src/Resources/Strings.resx @@ -535,6 +535,30 @@ 拖尾刷新率 + + 自定义 HTML 特效 + + + 选择 HTML 文件 + + + 恢复内置特效 + + + 使用自定义 HTML 时,下方内置视觉调节将不可用。 + + + (使用内置特效) + + + HTML 文件 (*.html;*.htm)|*.html;*.htm + + + 选择特效 HTML 文件 + + + index.html 为软件内置默认特效,不能作为自定义文件选用。请复制 custom-effect-template.html 后修改,或选择您自己的 HTML。 + WebView2 初始化失败: {0} diff --git a/src/UiLocalizer.cs b/src/UiLocalizer.cs index c0aa609..7514f91 100644 --- a/src/UiLocalizer.cs +++ b/src/UiLocalizer.cs @@ -91,6 +91,10 @@ public static void ApplyControlPanel(ControlPanelWindow w) w.TxtTrailRefresh.Text = Localization.Get("Visual_TrailRefresh"); w.TxtEffectColor.Text = Localization.Get("Visual_Color"); w.BtnPickColor.Content = Localization.Get("Visual_ChangeColor"); + w.TxtCustomHtmlTitle.Text = Localization.Get("CustomHtml_Title"); + w.BtnBrowseCustomHtml.Content = Localization.Get("CustomHtml_Browse"); + w.BtnClearCustomHtml.Content = Localization.Get("CustomHtml_ClearBuiltin"); + w.TxtCustomHtmlHint.Text = Localization.Get("CustomHtml_Hint"); w.TxtFilterTitle.Text = Localization.Get("Filter_Title"); w.CheckEnvironmentFilter.Content = Localization.Get("Filter_Enable"); diff --git a/src/Web/custom-effect-template.html b/src/Web/custom-effect-template.html new file mode 100644 index 0000000..81a1322 --- /dev/null +++ b/src/Web/custom-effect-template.html @@ -0,0 +1,107 @@ + + + + + + + + + + + + diff --git a/src/Web/custom-effect-test.html b/src/Web/custom-effect-test.html new file mode 100644 index 0000000..fc00a63 --- /dev/null +++ b/src/Web/custom-effect-test.html @@ -0,0 +1,125 @@ + + + + + + + + + + +