From dce5722e9630d20d5e492fde6bec8bf8ddabe667 Mon Sep 17 00:00:00 2001
From: CJK_mkp <113243675+CJKmkp@users.noreply.github.com>
Date: Wed, 13 Aug 2025 21:59:35 +0800
Subject: [PATCH 01/45] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=97=A5=E5=BF=97?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Ink Canvas/MainWindow.xaml.cs | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/Ink Canvas/MainWindow.xaml.cs b/Ink Canvas/MainWindow.xaml.cs
index 8aa1e679..2a3a5623 100644
--- a/Ink Canvas/MainWindow.xaml.cs
+++ b/Ink Canvas/MainWindow.xaml.cs
@@ -1801,7 +1801,6 @@ namespace Ink_Canvas
SetWindowLong(hwnd, GWL_EXSTYLE, exStyle | WS_EX_TOPMOST);
}
- LogHelper.WriteLogToFile("置顶维护: 重新设置窗口置顶", LogHelper.LogType.Trace);
}
}
catch (Exception ex)
@@ -1960,4 +1959,4 @@ namespace Ink_Canvas
#endregion
}
-}
\ No newline at end of file
+}
From 69023f98d9cea86284d1ae45ff756da3a5b59b5e Mon Sep 17 00:00:00 2001
From: CJK_mkp <113243675+CJKmkp@users.noreply.github.com>
Date: Wed, 13 Aug 2025 22:00:53 +0800
Subject: [PATCH 02/45] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=97=A5=E5=BF=97?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Ink Canvas/MainWindow.xaml.cs | 3 ---
1 file changed, 3 deletions(-)
diff --git a/Ink Canvas/MainWindow.xaml.cs b/Ink Canvas/MainWindow.xaml.cs
index 2a3a5623..31bc55a5 100644
--- a/Ink Canvas/MainWindow.xaml.cs
+++ b/Ink Canvas/MainWindow.xaml.cs
@@ -1702,9 +1702,6 @@ namespace Ink_Canvas
// 停止置顶维护定时器
StopTopmostMaintenance();
}
-
- // 添加调试日志
- LogHelper.WriteLogToFile($"应用窗口置顶: 启用置顶 (无焦点模式: {Settings.Advanced.IsNoFocusMode})", LogHelper.LogType.Trace);
}
else
{
From 5b4c966354d4ff7ecd56bff6e04f7a9708295612 Mon Sep 17 00:00:00 2001
From: CJK_mkp <113243675+CJKmkp@users.noreply.github.com>
Date: Wed, 13 Aug 2025 22:03:18 +0800
Subject: [PATCH 03/45] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=97=A5=E5=BF=97?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs | 9 ---------
1 file changed, 9 deletions(-)
diff --git a/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs b/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs
index 167b5556..bc433b70 100644
--- a/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs
+++ b/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs
@@ -2906,15 +2906,6 @@ namespace Ink_Canvas
// 设置高光位置
FloatingbarSelectionBG.Visibility = Visibility.Visible;
System.Windows.Controls.Canvas.SetLeft(FloatingbarSelectionBG, position);
-
- // 详细的调试信息
- string debugInfo = $"设置高光位置: {mode} -> {position:F2}, " +
- $"高光宽度: {actualHighlightWidth:F2}, " +
- $"快捷调色盘: {quickColorPaletteMode}, 宽度: {quickColorPaletteWidth:F2}, 总宽度: {quickColorPaletteTotalWidth:F2}, " +
- $"按钮宽度: cursor={cursorWidth:F2}, pen={penWidth:F2}, delete={deleteWidth:F2}, " +
- $"eraser={eraserWidth:F2}, eraserByStrokes={eraserByStrokesWidth:F2}, select={selectWidth:F2}";
-
- LogHelper.WriteLogToFile(debugInfo, LogHelper.LogType.Trace);
}
catch (Exception ex)
{
From 723c825df2136a764f61f64e2b8f293b3a546e73 Mon Sep 17 00:00:00 2001
From: CJK_mkp <113243675+CJKmkp@users.noreply.github.com>
Date: Mon, 18 Aug 2025 17:42:36 +0800
Subject: [PATCH 04/45] =?UTF-8?q?fix:=E5=85=B3=E6=9C=BA=E6=97=B6=E4=B8=8D?=
=?UTF-8?q?=E4=BF=9D=E5=AD=98=E4=BD=BF=E7=94=A8=E6=95=B0=E6=8D=AE?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Ink Canvas/App.xaml.cs | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/Ink Canvas/App.xaml.cs b/Ink Canvas/App.xaml.cs
index e3ac9b51..aed955f9 100644
--- a/Ink Canvas/App.xaml.cs
+++ b/Ink Canvas/App.xaml.cs
@@ -338,6 +338,13 @@ namespace Ink_Canvas
WriteCrashLog($"最后错误信息: {lastErrorMessage}");
}
}
+
+ // 新增:关机保存使用时间数据
+ private void SystemEvents_SessionEnding(object sender, SessionEndingEventArgs e)
+ {
+ string reason = e.Reason == SessionEndReasons.Logoff ? "用户注销" : "系统关机";
+ DeviceIdentifier.SaveUsageStatsOnShutdown();
+ }
// 新增:记录崩溃日志
private static void WriteCrashLog(string message)
From cce0b930ecbfe62a9a5dd55f3cffdf1bf6a380be Mon Sep 17 00:00:00 2001
From: CJK_mkp <113243675+CJKmkp@users.noreply.github.com>
Date: Mon, 18 Aug 2025 17:49:33 +0800
Subject: [PATCH 05/45] =?UTF-8?q?fix:=E5=85=B3=E6=9C=BA=E6=97=B6=E4=B8=8D?=
=?UTF-8?q?=E4=BF=9D=E5=AD=98=E4=BD=BF=E7=94=A8=E6=95=B0=E6=8D=AE?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Ink Canvas/Helpers/DeviceIdentifier.cs | 147 ++++++++++++++++++++++++-
1 file changed, 146 insertions(+), 1 deletion(-)
diff --git a/Ink Canvas/Helpers/DeviceIdentifier.cs b/Ink Canvas/Helpers/DeviceIdentifier.cs
index a82fe3a8..274d46e7 100644
--- a/Ink Canvas/Helpers/DeviceIdentifier.cs
+++ b/Ink Canvas/Helpers/DeviceIdentifier.cs
@@ -2745,5 +2745,150 @@ namespace Ink_Canvas.Helpers
return errorMsg;
}
}
+ ///
+ /// 关机时保存使用时间数据
+ ///
+ public static void SaveUsageStatsOnShutdown()
+ {
+ lock (fileLock) // 确保线程安全
+ {
+ try
+ {
+ // 1. 加载现有使用统计数据
+ UsageStats stats = LoadUsageStats();
+ if (stats == null)
+ {
+ stats = new UsageStats { DeviceId = DeviceId };
+ }
+
+ // 2. 计算本次会话时长
+ TimeSpan sessionDuration = DateTime.Now - App.appStartTime;
+ long sessionSeconds = (long)sessionDuration.TotalSeconds;
+
+ // 3. 更新统计数据
+ stats.TotalUsageSeconds += sessionSeconds;
+ stats.LaunchCount++;
+ stats.AverageSessionSeconds = stats.TotalUsageSeconds / (double)stats.LaunchCount;
+ stats.LastLaunchTime = DateTime.Now;
+
+ // 4. 保存到所有备份位置
+ SaveUsageStatsToAllLocations(stats);
+
+ LogHelper.WriteLogToFile($"使用时间数据已保存: 总时长 {stats.TotalUsageSeconds} 秒");
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"关机时保存使用时间数据失败: {ex.Message}", LogHelper.LogType.Error);
+ }
+ }
+ }
+
+ ///
+ /// 加载现有使用统计数据(从主文件或备份)
+ ///
+ private static UsageStats LoadUsageStats()
+ {
+ // 尝试从主文件加载
+ if (File.Exists(UsageStatsFilePath))
+ {
+ try
+ {
+ string json = File.ReadAllText(UsageStatsFilePath);
+ return JsonConvert.DeserializeObject(json);
+ }
+ catch
+ {
+ // 主文件损坏,尝试从备份加载
+ if (File.Exists(BackupUsageStatsPath))
+ {
+ try
+ {
+ string backupJson = File.ReadAllText(BackupUsageStatsPath);
+ return JsonConvert.DeserializeObject(backupJson);
+ }
+ catch
+ {
+ // 可继续尝试其他备份路径
+ return LoadFromOtherBackups();
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ ///
+ /// 从其他备份路径加载数据
+ ///
+ private static UsageStats LoadFromOtherBackups()
+ {
+ // 尝试二级备份
+ if (File.Exists(SecondaryUsageBackupPath))
+ {
+ try
+ {
+ return JsonConvert.DeserializeObject(File.ReadAllText(SecondaryUsageBackupPath));
+ }
+ catch { }
+ }
+
+ // 尝试三级备份
+ if (File.Exists(TertiaryUsageBackupPath))
+ {
+ try
+ {
+ return JsonConvert.DeserializeObject(File.ReadAllText(TertiaryUsageBackupPath));
+ }
+ catch { }
+ }
+
+ // 尝试四级备份
+ if (File.Exists(QuaternaryUsageBackupPath))
+ {
+ try
+ {
+ return JsonConvert.DeserializeObject(File.ReadAllText(QuaternaryUsageBackupPath));
+ }
+ catch { }
+ }
+
+ return null;
+ }
+
+ ///
+ /// 保存使用统计数据到所有备份位置
+ ///
+ private static void SaveUsageStatsToAllLocations(UsageStats stats)
+ {
+ string json = JsonConvert.SerializeObject(stats, Formatting.Indented);
+
+ // 保存到主文件
+ SaveToFile(UsageStatsFilePath, json);
+ // 保存到多重备份路径
+ SaveToFile(BackupUsageStatsPath, json);
+ SaveToFile(SecondaryUsageBackupPath, json);
+ SaveToFile(TertiaryUsageBackupPath, json);
+ SaveToFile(QuaternaryUsageBackupPath, json);
+ }
+
+ ///
+ /// 辅助方法:保存内容到文件(确保目录存在)
+ ///
+ private static void SaveToFile(string path, string content)
+ {
+ try
+ {
+ string dir = Path.GetDirectoryName(path);
+ if (!Directory.Exists(dir))
+ {
+ Directory.CreateDirectory(dir);
+ }
+ File.WriteAllText(path, content);
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"保存文件 {path} 失败: {ex.Message}", LogHelper.LogType.Warning);
+ }
+ }
}
-}
\ No newline at end of file
+}
From cc8863085952433231b683be430180e2c18d5541 Mon Sep 17 00:00:00 2001
From: CJK_mkp <113243675+CJKmkp@users.noreply.github.com>
Date: Mon, 18 Aug 2025 17:54:41 +0800
Subject: [PATCH 06/45] =?UTF-8?q?fix:=E5=85=B3=E6=9C=BA=E6=97=B6=E4=B8=8D?=
=?UTF-8?q?=E4=BF=9D=E5=AD=98=E4=BD=BF=E7=94=A8=E6=95=B0=E6=8D=AE?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Ink Canvas/Helpers/DeviceIdentifier.cs | 108 -------------------------
1 file changed, 108 deletions(-)
diff --git a/Ink Canvas/Helpers/DeviceIdentifier.cs b/Ink Canvas/Helpers/DeviceIdentifier.cs
index 274d46e7..0ee14e12 100644
--- a/Ink Canvas/Helpers/DeviceIdentifier.cs
+++ b/Ink Canvas/Helpers/DeviceIdentifier.cs
@@ -2782,113 +2782,5 @@ namespace Ink_Canvas.Helpers
}
}
}
-
- ///
- /// 加载现有使用统计数据(从主文件或备份)
- ///
- private static UsageStats LoadUsageStats()
- {
- // 尝试从主文件加载
- if (File.Exists(UsageStatsFilePath))
- {
- try
- {
- string json = File.ReadAllText(UsageStatsFilePath);
- return JsonConvert.DeserializeObject(json);
- }
- catch
- {
- // 主文件损坏,尝试从备份加载
- if (File.Exists(BackupUsageStatsPath))
- {
- try
- {
- string backupJson = File.ReadAllText(BackupUsageStatsPath);
- return JsonConvert.DeserializeObject(backupJson);
- }
- catch
- {
- // 可继续尝试其他备份路径
- return LoadFromOtherBackups();
- }
- }
- }
- }
- return null;
- }
-
- ///
- /// 从其他备份路径加载数据
- ///
- private static UsageStats LoadFromOtherBackups()
- {
- // 尝试二级备份
- if (File.Exists(SecondaryUsageBackupPath))
- {
- try
- {
- return JsonConvert.DeserializeObject(File.ReadAllText(SecondaryUsageBackupPath));
- }
- catch { }
- }
-
- // 尝试三级备份
- if (File.Exists(TertiaryUsageBackupPath))
- {
- try
- {
- return JsonConvert.DeserializeObject(File.ReadAllText(TertiaryUsageBackupPath));
- }
- catch { }
- }
-
- // 尝试四级备份
- if (File.Exists(QuaternaryUsageBackupPath))
- {
- try
- {
- return JsonConvert.DeserializeObject(File.ReadAllText(QuaternaryUsageBackupPath));
- }
- catch { }
- }
-
- return null;
- }
-
- ///
- /// 保存使用统计数据到所有备份位置
- ///
- private static void SaveUsageStatsToAllLocations(UsageStats stats)
- {
- string json = JsonConvert.SerializeObject(stats, Formatting.Indented);
-
- // 保存到主文件
- SaveToFile(UsageStatsFilePath, json);
- // 保存到多重备份路径
- SaveToFile(BackupUsageStatsPath, json);
- SaveToFile(SecondaryUsageBackupPath, json);
- SaveToFile(TertiaryUsageBackupPath, json);
- SaveToFile(QuaternaryUsageBackupPath, json);
- }
-
- ///
- /// 辅助方法:保存内容到文件(确保目录存在)
- ///
- private static void SaveToFile(string path, string content)
- {
- try
- {
- string dir = Path.GetDirectoryName(path);
- if (!Directory.Exists(dir))
- {
- Directory.CreateDirectory(dir);
- }
- File.WriteAllText(path, content);
- }
- catch (Exception ex)
- {
- LogHelper.WriteLogToFile($"保存文件 {path} 失败: {ex.Message}", LogHelper.LogType.Warning);
- }
- }
}
}
From 975b563b8d77f7e336fbc56da0c7e40348f6d1fe Mon Sep 17 00:00:00 2001
From: CJK_mkp <113243675+CJKmkp@users.noreply.github.com>
Date: Mon, 18 Aug 2025 17:57:56 +0800
Subject: [PATCH 07/45] =?UTF-8?q?fix:=E5=85=B3=E6=9C=BA=E6=97=B6=E4=B8=8D?=
=?UTF-8?q?=E4=BF=9D=E5=AD=98=E4=BD=BF=E7=94=A8=E6=95=B0=E6=8D=AE?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Ink Canvas/App.xaml.cs | 8 +-------
1 file changed, 1 insertion(+), 7 deletions(-)
diff --git a/Ink Canvas/App.xaml.cs b/Ink Canvas/App.xaml.cs
index aed955f9..04a78827 100644
--- a/Ink Canvas/App.xaml.cs
+++ b/Ink Canvas/App.xaml.cs
@@ -287,6 +287,7 @@ namespace Ink_Canvas
{
string reason = e.Reason == SessionEndReasons.Logoff ? "用户注销" : "系统关机";
WriteCrashLog($"系统会话即将结束: {reason}");
+ DeviceIdentifier.SaveUsageStatsOnShutdown();
}
// 新增:控制台取消事件处理
@@ -338,13 +339,6 @@ namespace Ink_Canvas
WriteCrashLog($"最后错误信息: {lastErrorMessage}");
}
}
-
- // 新增:关机保存使用时间数据
- private void SystemEvents_SessionEnding(object sender, SessionEndingEventArgs e)
- {
- string reason = e.Reason == SessionEndReasons.Logoff ? "用户注销" : "系统关机";
- DeviceIdentifier.SaveUsageStatsOnShutdown();
- }
// 新增:记录崩溃日志
private static void WriteCrashLog(string message)
From 502e2050711451cd885f1bedb2ab0e484abd2d3c Mon Sep 17 00:00:00 2001
From: CJK_mkp <113243675+CJKmkp@users.noreply.github.com>
Date: Mon, 18 Aug 2025 18:01:23 +0800
Subject: [PATCH 08/45] =?UTF-8?q?fix:=E5=85=B3=E6=9C=BA=E6=97=B6=E4=B8=8D?=
=?UTF-8?q?=E4=BF=9D=E5=AD=98=E4=BD=BF=E7=94=A8=E6=95=B0=E6=8D=AE?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Ink Canvas/App.xaml.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Ink Canvas/App.xaml.cs b/Ink Canvas/App.xaml.cs
index 04a78827..0f50976a 100644
--- a/Ink Canvas/App.xaml.cs
+++ b/Ink Canvas/App.xaml.cs
@@ -45,7 +45,7 @@ namespace Ink_Canvas
// 新增:进程ID
private static int currentProcessId = Process.GetCurrentProcess().Id;
// 新增:应用启动时间
- private static DateTime appStartTime = DateTime.Now;
+ internal static DateTime appStartTime { get; private set; }
// 新增:最后一次错误信息
private static string lastErrorMessage = string.Empty;
// 新增:是否已初始化崩溃监听器
From f331cb1b4d52b76d416d83e29a892d468623404d Mon Sep 17 00:00:00 2001
From: CJK_mkp <113243675+CJKmkp@users.noreply.github.com>
Date: Tue, 19 Aug 2025 17:41:42 +0800
Subject: [PATCH 09/45] fix:issue #110
---
Ink Canvas/MainWindow_cs/MW_TrayIcon.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Ink Canvas/MainWindow_cs/MW_TrayIcon.cs b/Ink Canvas/MainWindow_cs/MW_TrayIcon.cs
index ec79414c..96796023 100644
--- a/Ink Canvas/MainWindow_cs/MW_TrayIcon.cs
+++ b/Ink Canvas/MainWindow_cs/MW_TrayIcon.cs
@@ -84,7 +84,7 @@ namespace Ink_Canvas
startInfo.UseShellExecute = true;
// 启动进程但不等待
- Process.Start(startInfo);
+ Process.Start(new ProcessStartInfo(exePath, "-delay 2000") { UseShellExecute = true });
}
catch (Exception ex)
{
From 35cfd26ecea1e1118bab6645f4a169c893f7910b Mon Sep 17 00:00:00 2001
From: CJK_mkp <113243675+CJKmkp@users.noreply.github.com>
Date: Tue, 19 Aug 2025 17:52:02 +0800
Subject: [PATCH 10/45] =?UTF-8?q?fix:=E9=80=80=E5=87=BA=E4=B8=8D=E5=AE=8C?=
=?UTF-8?q?=E5=85=A8=E6=97=B6=E6=9B=B4=E6=96=B0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Ink Canvas/Helpers/AutoUpdateHelper.cs | 17 +++++++++--------
1 file changed, 9 insertions(+), 8 deletions(-)
diff --git a/Ink Canvas/Helpers/AutoUpdateHelper.cs b/Ink Canvas/Helpers/AutoUpdateHelper.cs
index 138c0090..d0910eb9 100644
--- a/Ink Canvas/Helpers/AutoUpdateHelper.cs
+++ b/Ink Canvas/Helpers/AutoUpdateHelper.cs
@@ -45,9 +45,9 @@ namespace Ink_Canvas.Helpers
new UpdateLineGroup
{
GroupName = "GitHub主线",
- VersionUrl = "https://github.com/InkCanvasForClass/community/raw/refs/heads/main/AutomaticUpdateVersionControl.txt",
- DownloadUrlFormat = "https://github.com/InkCanvasForClass/community/releases/download/{0}/InkCanvasForClass.CE.{0}.zip",
- LogUrl = "https://github.com/InkCanvasForClass/community/raw/refs/heads/main/UpdateLog.md"
+ VersionUrl = "https://bgithub.xyz/InkCanvasForClass/community/raw/refs/heads/main/AutomaticUpdateVersionControl.txt",
+ DownloadUrlFormat = "https://bgithub.xyz/InkCanvasForClass/community/releases/download/{0}/InkCanvasForClass.CE.{0}.zip",
+ LogUrl = "https://bgithub.xyz/InkCanvasForClass/community/raw/refs/heads/main/UpdateLog.md"
},
new UpdateLineGroup
{
@@ -80,9 +80,9 @@ namespace Ink_Canvas.Helpers
new UpdateLineGroup
{
GroupName = "GitHub主线",
- VersionUrl = "https://github.com/InkCanvasForClass/community-beta/raw/refs/heads/main/AutomaticUpdateVersionControl.txt",
- DownloadUrlFormat = "https://github.com/InkCanvasForClass/community-beta/releases/download/{0}/InkCanvasForClass.CE.{0}.zip",
- LogUrl = "https://github.com/InkCanvasForClass/community-beta/raw/refs/heads/main/UpdateLog.md"
+ VersionUrl = "https://bgithub.xyz/InkCanvasForClass/community-beta/raw/refs/heads/main/AutomaticUpdateVersionControl.txt",
+ DownloadUrlFormat = "https://bgithub.xyz/InkCanvasForClass/community-beta/releases/download/{0}/InkCanvasForClass.CE.{0}.zip",
+ LogUrl = "https://bgithub.xyz/InkCanvasForClass/community-beta/raw/refs/heads/main/UpdateLog.md"
},
new UpdateLineGroup
{
@@ -1195,7 +1195,7 @@ namespace Ink_Canvas.Helpers
StringBuilder batchContent = new StringBuilder();
batchContent.AppendLine("@echo off");
-
+
batchContent.AppendLine("echo Set objShell = CreateObject(\"WScript.Shell\") > \"%temp%\\hideme.vbs\"");
batchContent.AppendLine("echo objShell.Run \"cmd /c \"\"\" ^& WScript.Arguments(0) ^& \"\"\"\", 0, True >> \"%temp%\\hideme.vbs\"");
batchContent.AppendLine("echo Wscript.Sleep 100 >> \"%temp%\\hideme.vbs\"");
@@ -1210,6 +1210,7 @@ namespace Ink_Canvas.Helpers
batchContent.AppendLine($"echo goto CHECK_PROCESS >> \"{updateBatPath}\"");
batchContent.AppendLine($"echo ) >> \"{updateBatPath}\"");
+ batchContent.AppendLine($"echo timeout /t 1 /nobreak > nul >> \"{updateBatPath}\"");
batchContent.AppendLine($"echo echo Application closed, starting update process... >> \"{updateBatPath}\"");
batchContent.AppendLine($"echo timeout /t 2 /nobreak ^> nul >> \"{updateBatPath}\"");
@@ -1514,7 +1515,7 @@ namespace Ink_Canvas.Helpers
LogHelper.WriteLogToFile("AutoUpdate | 开始测试Windows 7 TLS连接...");
// 测试GitHub连接
- var testUrl = "https://github.com/InkCanvasForClass/community/raw/refs/heads/main/AutomaticUpdateVersionControl.txt";
+ var testUrl = "https://bgithub.xyz/InkCanvasForClass/community/raw/refs/heads/main/AutomaticUpdateVersionControl.txt";
using (var handler = new HttpClientHandler())
{
From 063f8b175162c85fefe0556732bc07230c448d22 Mon Sep 17 00:00:00 2001
From: CJK_mkp <113243675+CJKmkp@users.noreply.github.com>
Date: Tue, 19 Aug 2025 18:04:45 +0800
Subject: [PATCH 11/45] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=97=A5=E5=BF=97?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Ink Canvas/Helpers/DeviceIdentifier.cs | 2 --
1 file changed, 2 deletions(-)
diff --git a/Ink Canvas/Helpers/DeviceIdentifier.cs b/Ink Canvas/Helpers/DeviceIdentifier.cs
index 0ee14e12..5d1d9d67 100644
--- a/Ink Canvas/Helpers/DeviceIdentifier.cs
+++ b/Ink Canvas/Helpers/DeviceIdentifier.cs
@@ -2773,8 +2773,6 @@ namespace Ink_Canvas.Helpers
// 4. 保存到所有备份位置
SaveUsageStatsToAllLocations(stats);
-
- LogHelper.WriteLogToFile($"使用时间数据已保存: 总时长 {stats.TotalUsageSeconds} 秒");
}
catch (Exception ex)
{
From f94d81ad20a6bd23a097f45326efff1e0f6c8a91 Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Sat, 23 Aug 2025 02:44:14 +0000
Subject: [PATCH 12/45] docs: update README.md
---
README.md | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 5887da59..3e09af86 100644
--- a/README.md
+++ b/README.md
@@ -85,6 +85,7 @@
 CJK_mkp 🚧 📖 💻 |
+  Hydrogen 💻 |
 CreeperAWA 💻 |
 2,2,3-三甲基戊烷 📝 📖 🎨 |
 Alan-CRL 💻 🚇 📖 💵 |
@@ -92,7 +93,7 @@
 Awesome Iwb 📖 |
-  PrefacedCorg 💻 |
+  PrefacedCorg 💻 🎨 |
From 68ea32385536468b0d94c0ef2c5cf71fc8ac023f Mon Sep 17 00:00:00 2001
From: "allcontributors[bot]"
<46447321+allcontributors[bot]@users.noreply.github.com>
Date: Sat, 23 Aug 2025 02:44:15 +0000
Subject: [PATCH 13/45] docs: update .all-contributorsrc
---
.all-contributorsrc | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/.all-contributorsrc b/.all-contributorsrc
index 41dcfa6e..3ac1bb16 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -86,7 +86,8 @@
"avatar_url": "https://avatars.githubusercontent.com/u/129855423?v=4",
"profile": "https://github.com/PrefacedCorg",
"contributions": [
- "code"
+ "code",
+ "design"
]
}
]
From aba6c18a2515411d081d5b8e229aa51e490304e6 Mon Sep 17 00:00:00 2001
From: CJKmkp <2564608840@qq.com>
Date: Sat, 23 Aug 2025 18:24:24 +0800
Subject: [PATCH 14/45] fix:issue #133
---
Ink Canvas/MainWindow_cs/MW_TouchEvents.cs | 186 +++++++++++++++++++--
1 file changed, 172 insertions(+), 14 deletions(-)
diff --git a/Ink Canvas/MainWindow_cs/MW_TouchEvents.cs b/Ink Canvas/MainWindow_cs/MW_TouchEvents.cs
index 49b8aeb8..44a9671d 100644
--- a/Ink Canvas/MainWindow_cs/MW_TouchEvents.cs
+++ b/Ink Canvas/MainWindow_cs/MW_TouchEvents.cs
@@ -1,6 +1,7 @@
using Ink_Canvas.Helpers;
using System;
using System.Collections.Generic;
+using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
@@ -343,6 +344,10 @@ namespace Ink_Canvas
private InkCanvasEditingMode palmEraserLastEditingMode = InkCanvasEditingMode.Ink;
private bool palmEraserLastIsHighlighter;
private bool palmEraserWasEnabledBeforeMultiTouch;
+ private bool palmEraserTouchDownHandled = false; // 新增:标记手掌擦触摸按下是否已处理
+ private DateTime palmEraserActivationTime; // 新增:记录手掌擦激活时间
+ private const int PALM_ERASER_TIMEOUT_MS = 5000; // 新增:手掌擦超时时间(5秒)
+ private System.Windows.Threading.DispatcherTimer palmEraserRecoveryTimer; // 新增:手掌擦恢复定时器
private void inkCanvas_PreviewTouchDown(object sender, TouchEventArgs e)
{
@@ -395,8 +400,8 @@ namespace Ink_Canvas
BlackboardUIGridForInkReplay.IsHitTestVisible = false;
dec.Add(e.TouchDevice.Id);
- // Palm Eraser 逻辑
- if (Settings.Canvas.EnablePalmEraser && dec.Count >= 2 && !isPalmEraserActive)
+ // Palm Eraser 逻辑 - 修复:只在触摸按下时处理一次,避免重复触发
+ if (Settings.Canvas.EnablePalmEraser && dec.Count >= 2 && !isPalmEraserActive && !palmEraserTouchDownHandled)
{
var bounds = e.GetTouchPoint(inkCanvas).Bounds;
double palmThreshold = 40; // 触摸面积阈值,可根据实际调整
@@ -408,6 +413,11 @@ namespace Ink_Canvas
// 切换为橡皮擦
EraserIcon_Click(null, null);
isPalmEraserActive = true;
+ palmEraserActivationTime = DateTime.Now; // 记录激活时间
+ palmEraserTouchDownHandled = true; // 标记已处理
+
+ // 启动恢复定时器,防止卡死
+ StartPalmEraserRecoveryTimer();
}
}
@@ -474,23 +484,86 @@ namespace Ink_Canvas
{
// 恢复高光状态
drawingAttributes.IsHighlighter = palmEraserLastIsHighlighter;
- // 恢复编辑模式
- if (inkCanvas.EditingMode == InkCanvasEditingMode.EraseByPoint)
+ // 恢复编辑模式 - 修复:确保正确恢复状态
+ try
{
- if (palmEraserLastEditingMode == InkCanvasEditingMode.Ink)
+ if (inkCanvas.EditingMode == InkCanvasEditingMode.EraseByPoint)
{
- PenIcon_Click(null, null);
- }
- else if (palmEraserLastEditingMode == InkCanvasEditingMode.Select)
- {
- SymbolIconSelect_MouseUp(null, null);
- }
- else
- {
- inkCanvas.EditingMode = palmEraserLastEditingMode;
+ if (palmEraserLastEditingMode == InkCanvasEditingMode.Ink)
+ {
+ PenIcon_Click(null, null);
+ }
+ else if (palmEraserLastEditingMode == InkCanvasEditingMode.Select)
+ {
+ SymbolIconSelect_MouseUp(null, null);
+ }
+ else
+ {
+ inkCanvas.EditingMode = palmEraserLastEditingMode;
+ }
}
}
+ catch (Exception ex)
+ {
+ // 如果恢复失败,强制切换到批注模式
+ Trace.WriteLine($"Palm eraser recovery failed: {ex.Message}, forcing to Ink mode");
+ inkCanvas.EditingMode = InkCanvasEditingMode.Ink;
+ }
+
+ // 重置手掌擦状态
isPalmEraserActive = false;
+ palmEraserTouchDownHandled = false;
+
+ // 停止恢复定时器
+ StopPalmEraserRecoveryTimer();
+
+ // 确保触摸事件能正常响应
+ inkCanvas.IsHitTestVisible = true;
+ inkCanvas.IsManipulationEnabled = true;
+ }
+
+ // 新增:超时检测 - 如果手掌擦激活时间过长,强制重置状态
+ if (isPalmEraserActive && dec.Count == 0)
+ {
+ var timeSinceActivation = DateTime.Now - palmEraserActivationTime;
+ if (timeSinceActivation.TotalMilliseconds > PALM_ERASER_TIMEOUT_MS)
+ {
+ Trace.WriteLine($"Palm eraser timeout detected ({timeSinceActivation.TotalMilliseconds}ms), forcing recovery");
+
+ // 强制恢复状态
+ try
+ {
+ if (inkCanvas.EditingMode == InkCanvasEditingMode.EraseByPoint)
+ {
+ if (palmEraserLastEditingMode == InkCanvasEditingMode.Ink)
+ {
+ PenIcon_Click(null, null);
+ }
+ else if (palmEraserLastEditingMode == InkCanvasEditingMode.Select)
+ {
+ SymbolIconSelect_MouseUp(null, null);
+ }
+ else
+ {
+ inkCanvas.EditingMode = palmEraserLastEditingMode;
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ Trace.WriteLine($"Palm eraser timeout recovery failed: {ex.Message}, forcing to Ink mode");
+ inkCanvas.EditingMode = InkCanvasEditingMode.Ink;
+ }
+
+ // 重置所有手掌擦状态
+ isPalmEraserActive = false;
+ palmEraserTouchDownHandled = false;
+ inkCanvas.IsHitTestVisible = true;
+ inkCanvas.IsManipulationEnabled = true;
+
+ // 停止恢复定时器
+ StopPalmEraserRecoveryTimer();
+ }
}
// 修复:几何绘制模式下,触摸抬手时应该正确处理,而不是简单模拟鼠标事件
if (drawingShapeMode != 0)
@@ -551,6 +624,16 @@ namespace Ink_Canvas
{
inkCanvas.EditingMode = lastInkCanvasEditingMode;
}
+
+ // 修复:确保手掌擦除后触摸事件能正常响应
+ if (isPalmEraserActive)
+ {
+ // 如果手掌擦还在激活状态但触摸点已清空,强制重置状态
+ isPalmEraserActive = false;
+ palmEraserTouchDownHandled = false;
+ inkCanvas.IsHitTestVisible = true;
+ inkCanvas.IsManipulationEnabled = true;
+ }
}
}
inkCanvas.Opacity = 1;
@@ -753,5 +836,80 @@ namespace Ink_Canvas
ToggleSwitchEnablePalmEraser.IsOn = false;
}
}
+
+ ///
+ /// 启动手掌擦恢复定时器,防止卡死状态
+ ///
+ private void StartPalmEraserRecoveryTimer()
+ {
+ if (palmEraserRecoveryTimer == null)
+ {
+ palmEraserRecoveryTimer = new System.Windows.Threading.DispatcherTimer();
+ palmEraserRecoveryTimer.Interval = TimeSpan.FromMilliseconds(1000); // 每秒检查一次
+ palmEraserRecoveryTimer.Tick += PalmEraserRecoveryTimer_Tick;
+ }
+
+ palmEraserRecoveryTimer.Start();
+ }
+
+ ///
+ /// 停止手掌擦恢复定时器
+ ///
+ private void StopPalmEraserRecoveryTimer()
+ {
+ if (palmEraserRecoveryTimer != null)
+ {
+ palmEraserRecoveryTimer.Stop();
+ }
+ }
+
+ ///
+ /// 手掌擦恢复定时器事件处理
+ ///
+ private void PalmEraserRecoveryTimer_Tick(object sender, EventArgs e)
+ {
+ if (!isPalmEraserActive) return;
+
+ // 检查是否超时
+ var timeSinceActivation = DateTime.Now - palmEraserActivationTime;
+ if (timeSinceActivation.TotalMilliseconds > PALM_ERASER_TIMEOUT_MS)
+ {
+ Trace.WriteLine($"Palm eraser recovery timer triggered, forcing recovery after {timeSinceActivation.TotalMilliseconds}ms");
+
+ // 强制恢复状态
+ try
+ {
+ if (inkCanvas.EditingMode == InkCanvasEditingMode.EraseByPoint)
+ {
+ if (palmEraserLastEditingMode == InkCanvasEditingMode.Ink)
+ {
+ PenIcon_Click(null, null);
+ }
+ else if (palmEraserLastEditingMode == InkCanvasEditingMode.Select)
+ {
+ SymbolIconSelect_MouseUp(null, null);
+ }
+ else
+ {
+ inkCanvas.EditingMode = palmEraserLastEditingMode;
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ Trace.WriteLine($"Palm eraser recovery timer failed: {ex.Message}, forcing to Ink mode");
+ inkCanvas.EditingMode = InkCanvasEditingMode.Ink;
+ }
+
+ // 重置所有手掌擦状态
+ isPalmEraserActive = false;
+ palmEraserTouchDownHandled = false;
+ inkCanvas.IsHitTestVisible = true;
+ inkCanvas.IsManipulationEnabled = true;
+
+ // 停止定时器
+ StopPalmEraserRecoveryTimer();
+ }
+ }
}
}
From c86ce00a1744d821670c8c0c2199f83b78bdab4c Mon Sep 17 00:00:00 2001
From: CJKmkp <2564608840@qq.com>
Date: Sat, 23 Aug 2025 18:29:24 +0800
Subject: [PATCH 15/45] =?UTF-8?q?fix:=E5=BF=AB=E6=8D=B7=E8=B0=83=E8=89=B2?=
=?UTF-8?q?=E6=9D=BF=E4=B8=8D=E6=94=AF=E6=8C=81=E8=8D=A7=E5=85=89=E7=AC=94?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../MainWindow_cs/MW_FloatingBarIcons.cs | 88 +++++++++++++++----
1 file changed, 72 insertions(+), 16 deletions(-)
diff --git a/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs b/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs
index bc433b70..a6799df9 100644
--- a/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs
+++ b/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs
@@ -1993,6 +1993,59 @@ namespace Ink_Canvas
drawingAttributes.Color = color;
inkCanvas.DefaultDrawingAttributes.Color = color;
+ // 如果当前是荧光笔模式,同时更新荧光笔颜色和属性
+ if (penType == 1)
+ {
+ // 根据颜色设置对应的荧光笔颜色索引
+ if (color == Colors.White || IsColorSimilar(color, Color.FromRgb(250, 250, 250), 10))
+ {
+ highlighterColor = 101; // 白色荧光笔
+ }
+ else if (color == Colors.Black)
+ {
+ highlighterColor = 100; // 黑色荧光笔
+ }
+ else if (color == Colors.Yellow || IsColorSimilar(color, Color.FromRgb(234, 179, 8), 15) ||
+ IsColorSimilar(color, Color.FromRgb(250, 204, 21), 15) ||
+ IsColorSimilar(color, Color.FromRgb(253, 224, 71), 15))
+ {
+ highlighterColor = 103; // 黄色荧光笔
+ }
+ else if (color == Color.FromRgb(255, 165, 0) || IsColorSimilar(color, Color.FromRgb(249, 115, 22), 15) ||
+ IsColorSimilar(color, Color.FromRgb(234, 88, 12), 15))
+ {
+ highlighterColor = 109; // 橙色荧光笔
+ }
+ else if (color == Color.FromRgb(37, 99, 235))
+ {
+ highlighterColor = 106; // 蓝色荧光笔
+ }
+ else if (color == Colors.Red || IsColorSimilar(color, Color.FromRgb(220, 38, 38), 15) ||
+ IsColorSimilar(color, Color.FromRgb(239, 68, 68), 15))
+ {
+ highlighterColor = 102; // 红色荧光笔
+ }
+ else if (color == Colors.Green || IsColorSimilar(color, Color.FromRgb(22, 163, 74), 15))
+ {
+ highlighterColor = 104; // 绿色荧光笔
+ }
+ else if (color == Color.FromRgb(147, 51, 234))
+ {
+ highlighterColor = 107; // 紫色荧光笔
+ }
+
+ // 确保荧光笔属性正确设置
+ drawingAttributes.Width = Settings.Canvas.HighlighterWidth / 2;
+ drawingAttributes.Height = Settings.Canvas.HighlighterWidth;
+ drawingAttributes.StylusTip = StylusTip.Rectangle;
+ drawingAttributes.IsHighlighter = true;
+
+ inkCanvas.DefaultDrawingAttributes.Width = Settings.Canvas.HighlighterWidth / 2;
+ inkCanvas.DefaultDrawingAttributes.Height = Settings.Canvas.HighlighterWidth;
+ inkCanvas.DefaultDrawingAttributes.StylusTip = StylusTip.Rectangle;
+ inkCanvas.DefaultDrawingAttributes.IsHighlighter = true;
+ }
+
// 更新颜色状态
if (currentMode == 0)
{
@@ -2047,50 +2100,53 @@ namespace Ink_Canvas
QuickColorGreenCheckSingle.Visibility = Visibility.Collapsed;
// 显示当前选中颜色的check图标
- if (IsColorSimilar(selectedColor, Colors.White, 10) || IsColorSimilar(selectedColor, Color.FromRgb(250, 250, 250), 10))
+ // 在荧光笔模式下,使用更宽松的颜色匹配
+ int tolerance = (penType == 1) ? 25 : 15; // 荧光笔模式使用更大的容差
+
+ if (IsColorSimilar(selectedColor, Colors.White, tolerance) || IsColorSimilar(selectedColor, Color.FromRgb(250, 250, 250), tolerance))
{
QuickColorWhiteCheck.Visibility = Visibility.Visible;
QuickColorWhiteCheckSingle.Visibility = Visibility.Visible;
}
- else if (IsColorSimilar(selectedColor, Colors.Black, 10))
+ else if (IsColorSimilar(selectedColor, Colors.Black, tolerance))
{
QuickColorBlackCheck.Visibility = Visibility.Visible;
QuickColorBlackCheckSingle.Visibility = Visibility.Visible;
}
- else if (IsColorSimilar(selectedColor, Colors.Yellow, 15) ||
- IsColorSimilar(selectedColor, Color.FromRgb(234, 179, 8), 15) ||
- IsColorSimilar(selectedColor, Color.FromRgb(250, 204, 21), 15) ||
- IsColorSimilar(selectedColor, Color.FromRgb(253, 224, 71), 15))
+ else if (IsColorSimilar(selectedColor, Colors.Yellow, tolerance) ||
+ IsColorSimilar(selectedColor, Color.FromRgb(234, 179, 8), tolerance) ||
+ IsColorSimilar(selectedColor, Color.FromRgb(250, 204, 21), tolerance) ||
+ IsColorSimilar(selectedColor, Color.FromRgb(253, 224, 71), tolerance))
{
QuickColorYellowCheck.Visibility = Visibility.Visible;
QuickColorYellowCheckSingle.Visibility = Visibility.Visible;
}
- else if (IsColorSimilar(selectedColor, Color.FromRgb(255, 165, 0), 15) ||
- IsColorSimilar(selectedColor, Color.FromRgb(249, 115, 22), 15) ||
- IsColorSimilar(selectedColor, Color.FromRgb(234, 88, 12), 15))
+ else if (IsColorSimilar(selectedColor, Color.FromRgb(255, 165, 0), tolerance) ||
+ IsColorSimilar(selectedColor, Color.FromRgb(249, 115, 22), tolerance) ||
+ IsColorSimilar(selectedColor, Color.FromRgb(234, 88, 12), tolerance))
{
QuickColorOrangeCheck.Visibility = Visibility.Visible;
QuickColorOrangeCheckSingle.Visibility = Visibility.Visible;
}
- else if (IsColorSimilar(selectedColor, Color.FromRgb(37, 99, 235), 15))
+ else if (IsColorSimilar(selectedColor, Color.FromRgb(37, 99, 235), tolerance))
{
QuickColorBlueCheck.Visibility = Visibility.Visible;
// 单行显示模式没有蓝色,所以不设置单行的check
}
- else if (IsColorSimilar(selectedColor, Colors.Red, 15) ||
- IsColorSimilar(selectedColor, Color.FromRgb(220, 38, 38), 15) ||
- IsColorSimilar(selectedColor, Color.FromRgb(239, 68, 68), 15))
+ else if (IsColorSimilar(selectedColor, Colors.Red, tolerance) ||
+ IsColorSimilar(selectedColor, Color.FromRgb(220, 38, 38), tolerance) ||
+ IsColorSimilar(selectedColor, Color.FromRgb(239, 68, 68), tolerance))
{
QuickColorRedCheck.Visibility = Visibility.Visible;
QuickColorRedCheckSingle.Visibility = Visibility.Visible;
}
- else if (IsColorSimilar(selectedColor, Colors.Green, 15) ||
- IsColorSimilar(selectedColor, Color.FromRgb(22, 163, 74), 15))
+ else if (IsColorSimilar(selectedColor, Colors.Green, tolerance) ||
+ IsColorSimilar(selectedColor, Color.FromRgb(22, 163, 74), tolerance))
{
QuickColorGreenCheck.Visibility = Visibility.Visible;
QuickColorGreenCheckSingle.Visibility = Visibility.Visible;
}
- else if (IsColorSimilar(selectedColor, Color.FromRgb(147, 51, 234), 15))
+ else if (IsColorSimilar(selectedColor, Color.FromRgb(147, 51, 234), tolerance))
{
QuickColorPurpleCheck.Visibility = Visibility.Visible;
// 单行显示模式没有紫色,所以不设置单行的check
From 84edb7bbe687c5c19c103581883b8500ca99b884 Mon Sep 17 00:00:00 2001
From: CJKmkp <2564608840@qq.com>
Date: Sat, 23 Aug 2025 18:39:12 +0800
Subject: [PATCH 16/45] =?UTF-8?q?fix:=E5=BF=AB=E6=8D=B7=E8=B0=83=E8=89=B2?=
=?UTF-8?q?=E6=9D=BF=E4=B8=8D=E6=94=AF=E6=8C=81=E8=8D=A7=E5=85=89=E7=AC=94?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Ink Canvas/MainWindow_cs/MW_Colors.cs | 3 +++
.../MainWindow_cs/MW_FloatingBarIcons.cs | 22 ++++++++++++++-----
2 files changed, 20 insertions(+), 5 deletions(-)
diff --git a/Ink Canvas/MainWindow_cs/MW_Colors.cs b/Ink Canvas/MainWindow_cs/MW_Colors.cs
index 07b4570a..4c003865 100644
--- a/Ink Canvas/MainWindow_cs/MW_Colors.cs
+++ b/Ink Canvas/MainWindow_cs/MW_Colors.cs
@@ -595,6 +595,9 @@ namespace Ink_Canvas
drawingAttributes.Height = Settings.Canvas.HighlighterWidth;
drawingAttributes.StylusTip = StylusTip.Rectangle;
drawingAttributes.IsHighlighter = true;
+
+ // 确保荧光笔模式切换后正确更新颜色和快捷调色板指示器
+ ColorSwitchCheck();
}
private void BtnColorBlack_Click(object sender, RoutedEventArgs e)
diff --git a/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs b/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs
index a6799df9..9d32dd4e 100644
--- a/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs
+++ b/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs
@@ -2011,8 +2011,10 @@ namespace Ink_Canvas
{
highlighterColor = 103; // 黄色荧光笔
}
- else if (color == Color.FromRgb(255, 165, 0) || IsColorSimilar(color, Color.FromRgb(249, 115, 22), 15) ||
- IsColorSimilar(color, Color.FromRgb(234, 88, 12), 15))
+ else if (color == Color.FromRgb(255, 165, 0) || IsColorSimilar(color, Color.FromRgb(249, 115, 22), 20) ||
+ IsColorSimilar(color, Color.FromRgb(234, 88, 12), 20) ||
+ IsColorSimilar(color, Color.FromRgb(251, 146, 60), 20) ||
+ IsColorSimilar(color, Color.FromRgb(253, 126, 20), 20))
{
highlighterColor = 109; // 橙色荧光笔
}
@@ -2044,6 +2046,9 @@ namespace Ink_Canvas
inkCanvas.DefaultDrawingAttributes.Height = Settings.Canvas.HighlighterWidth;
inkCanvas.DefaultDrawingAttributes.StylusTip = StylusTip.Rectangle;
inkCanvas.DefaultDrawingAttributes.IsHighlighter = true;
+
+ // 确保荧光笔颜色索引正确更新
+ inkCanvas.DefaultDrawingAttributes.Color = drawingAttributes.Color;
}
// 更新颜色状态
@@ -2077,6 +2082,12 @@ namespace Ink_Canvas
// 更新颜色显示
ColorSwitchCheck();
+
+ // 如果当前是荧光笔模式,调用ColorSwitchCheck确保颜色索引正确更新
+ if (penType == 1)
+ {
+ ColorSwitchCheck();
+ }
}
private void UpdateQuickColorPaletteIndicator(Color selectedColor)
@@ -2123,7 +2134,9 @@ namespace Ink_Canvas
}
else if (IsColorSimilar(selectedColor, Color.FromRgb(255, 165, 0), tolerance) ||
IsColorSimilar(selectedColor, Color.FromRgb(249, 115, 22), tolerance) ||
- IsColorSimilar(selectedColor, Color.FromRgb(234, 88, 12), tolerance))
+ IsColorSimilar(selectedColor, Color.FromRgb(234, 88, 12), tolerance) ||
+ IsColorSimilar(selectedColor, Color.FromRgb(251, 146, 60), tolerance) ||
+ IsColorSimilar(selectedColor, Color.FromRgb(253, 126, 20), tolerance))
{
QuickColorOrangeCheck.Visibility = Visibility.Visible;
QuickColorOrangeCheckSingle.Visibility = Visibility.Visible;
@@ -2140,8 +2153,7 @@ namespace Ink_Canvas
QuickColorRedCheck.Visibility = Visibility.Visible;
QuickColorRedCheckSingle.Visibility = Visibility.Visible;
}
- else if (IsColorSimilar(selectedColor, Colors.Green, tolerance) ||
- IsColorSimilar(selectedColor, Color.FromRgb(22, 163, 74), tolerance))
+ else if (IsColorSimilar(selectedColor, Color.FromRgb(22, 163, 74), tolerance))
{
QuickColorGreenCheck.Visibility = Visibility.Visible;
QuickColorGreenCheckSingle.Visibility = Visibility.Visible;
From 9e63a3f49bb7987441087d9722e166b0ea5d7946 Mon Sep 17 00:00:00 2001
From: CJKmkp <2564608840@qq.com>
Date: Sat, 23 Aug 2025 18:43:47 +0800
Subject: [PATCH 17/45] =?UTF-8?q?fix:=E5=BF=AB=E6=8D=B7=E8=B0=83=E8=89=B2?=
=?UTF-8?q?=E6=9D=BF=E4=B8=8D=E6=94=AF=E6=8C=81=E8=8D=A7=E5=85=89=E7=AC=94?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs b/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs
index 9d32dd4e..dd3b4191 100644
--- a/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs
+++ b/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs
@@ -836,7 +836,7 @@ namespace Ink_Canvas
break;
case "QuickColorOrange":
case "QuickColorOrangeSingle":
- border.Background = new SolidColorBrush(Color.FromRgb(255, 165, 0));
+ border.Background = new SolidColorBrush(Color.FromRgb(251, 150, 80));
break;
case "QuickColorYellow":
case "QuickColorYellowSingle":
@@ -1948,7 +1948,7 @@ namespace Ink_Canvas
private void QuickColorOrange_Click(object sender, RoutedEventArgs e)
{
- SetQuickColor(Color.FromRgb(255, 165, 0)); // 橙色
+ SetQuickColor(Color.FromRgb(251, 150, 80)); // 橙色
}
private void QuickColorYellow_Click(object sender, RoutedEventArgs e)
@@ -2011,7 +2011,7 @@ namespace Ink_Canvas
{
highlighterColor = 103; // 黄色荧光笔
}
- else if (color == Color.FromRgb(255, 165, 0) || IsColorSimilar(color, Color.FromRgb(249, 115, 22), 20) ||
+ else if (color == Color.FromRgb(255, 165, 0) || color == Color.FromRgb(251, 150, 80) || IsColorSimilar(color, Color.FromRgb(249, 115, 22), 20) ||
IsColorSimilar(color, Color.FromRgb(234, 88, 12), 20) ||
IsColorSimilar(color, Color.FromRgb(251, 146, 60), 20) ||
IsColorSimilar(color, Color.FromRgb(253, 126, 20), 20))
@@ -2056,7 +2056,7 @@ namespace Ink_Canvas
{
// 桌面模式
if (color == Colors.White) lastDesktopInkColor = 5;
- else if (color == Color.FromRgb(255, 165, 0)) lastDesktopInkColor = 8; // 橙色
+ else if (color == Color.FromRgb(251, 150, 80)) lastDesktopInkColor = 8; // 橙色
else if (color == Colors.Yellow) lastDesktopInkColor = 4;
else if (color == Colors.Black) lastDesktopInkColor = 0;
else if (color == Color.FromRgb(37, 99, 235)) lastDesktopInkColor = 3; // 蓝色
@@ -2068,7 +2068,7 @@ namespace Ink_Canvas
{
// 白板模式
if (color == Colors.White) lastBoardInkColor = 5;
- else if (color == Color.FromRgb(255, 165, 0)) lastBoardInkColor = 8; // 橙色
+ else if (color == Color.FromRgb(251, 150, 80)) lastBoardInkColor = 8; // 橙色
else if (color == Colors.Yellow) lastBoardInkColor = 4;
else if (color == Colors.Black) lastBoardInkColor = 0;
else if (color == Color.FromRgb(37, 99, 235)) lastBoardInkColor = 3; // 蓝色
@@ -2133,6 +2133,7 @@ namespace Ink_Canvas
QuickColorYellowCheckSingle.Visibility = Visibility.Visible;
}
else if (IsColorSimilar(selectedColor, Color.FromRgb(255, 165, 0), tolerance) ||
+ IsColorSimilar(selectedColor, Color.FromRgb(251, 150, 80), tolerance) ||
IsColorSimilar(selectedColor, Color.FromRgb(249, 115, 22), tolerance) ||
IsColorSimilar(selectedColor, Color.FromRgb(234, 88, 12), tolerance) ||
IsColorSimilar(selectedColor, Color.FromRgb(251, 146, 60), tolerance) ||
From 8f01b6c5fe1c82993782708fc95b874cc69043c1 Mon Sep 17 00:00:00 2001
From: CJKmkp <2564608840@qq.com>
Date: Sat, 23 Aug 2025 18:51:16 +0800
Subject: [PATCH 18/45] =?UTF-8?q?fix:=E5=88=87=E6=8D=A2=E6=97=B6=E8=8D=A7?=
=?UTF-8?q?=E5=85=89=E7=AC=94=E7=8A=B6=E6=80=81=E5=BC=82=E5=B8=B8?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../MainWindow_cs/MW_FloatingBarIcons.cs | 71 ++++++++++++++-----
1 file changed, 55 insertions(+), 16 deletions(-)
diff --git a/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs b/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs
index dd3b4191..eae5db73 100644
--- a/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs
+++ b/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs
@@ -1724,13 +1724,27 @@ namespace Ink_Canvas
}
}
- // 修复:从线擦切换到批注时,重置为默认笔模式(非高光显示)
+ // 修复:从线擦切换到批注时,保持之前的笔类型状态
+ // 如果之前是荧光笔模式,则保持荧光笔状态;否则重置为默认笔模式
forceEraser = false;
forcePointEraser = false;
drawingShapeMode = 0;
- penType = 0;
- drawingAttributes.IsHighlighter = false;
- drawingAttributes.StylusTip = StylusTip.Ellipse;
+
+ // 保持之前的笔类型状态,而不是强制重置
+ if (!wasHighlighter)
+ {
+ penType = 0;
+ drawingAttributes.IsHighlighter = false;
+ drawingAttributes.StylusTip = StylusTip.Ellipse;
+ }
+ // 如果之前是荧光笔模式,则保持荧光笔属性
+ else if (penType == 1)
+ {
+ drawingAttributes.IsHighlighter = true;
+ drawingAttributes.StylusTip = StylusTip.Rectangle;
+ drawingAttributes.Width = Settings.Canvas.HighlighterWidth / 2;
+ drawingAttributes.Height = Settings.Canvas.HighlighterWidth;
+ }
ColorSwitchCheck();
HideSubPanels("pen", true);
@@ -1742,13 +1756,26 @@ namespace Ink_Canvas
// 修复:从线擦切换到批注时,确保正确重置状态
if (forceEraser)
{
- // 从橡皮擦模式切换过来,重置为默认笔模式
+ // 从橡皮擦模式切换过来,保持之前的笔类型状态
forceEraser = false;
forcePointEraser = false;
drawingShapeMode = 0;
- penType = 0;
- drawingAttributes.IsHighlighter = false;
- drawingAttributes.StylusTip = StylusTip.Ellipse;
+
+ // 保持之前的笔类型状态,而不是强制重置
+ if (!wasHighlighter)
+ {
+ penType = 0;
+ drawingAttributes.IsHighlighter = false;
+ drawingAttributes.StylusTip = StylusTip.Ellipse;
+ }
+ // 如果之前是荧光笔模式,则保持荧光笔属性
+ else if (penType == 1)
+ {
+ drawingAttributes.IsHighlighter = true;
+ drawingAttributes.StylusTip = StylusTip.Rectangle;
+ drawingAttributes.Width = Settings.Canvas.HighlighterWidth / 2;
+ drawingAttributes.Height = Settings.Canvas.HighlighterWidth;
+ }
// 在非白板模式下,从线擦切换到批注时不直接弹出子面板
if (currentMode != 1)
@@ -1800,13 +1827,26 @@ namespace Ink_Canvas
}
inkCanvas.EditingMode = InkCanvasEditingMode.Ink;
- // 修复:从线擦切换到批注时,重置为默认笔模式(非高光显示)
+ // 修复:从线擦切换到批注时,保持之前的笔类型状态
forceEraser = false;
forcePointEraser = false;
drawingShapeMode = 0;
- penType = 0;
- drawingAttributes.IsHighlighter = false;
- drawingAttributes.StylusTip = StylusTip.Ellipse;
+
+ // 保持之前的笔类型状态,而不是强制重置
+ if (!wasHighlighter)
+ {
+ penType = 0;
+ drawingAttributes.IsHighlighter = false;
+ drawingAttributes.StylusTip = StylusTip.Ellipse;
+ }
+ // 如果之前是荧光笔模式,则保持荧光笔属性
+ else if (penType == 1)
+ {
+ drawingAttributes.IsHighlighter = true;
+ drawingAttributes.StylusTip = StylusTip.Rectangle;
+ drawingAttributes.Width = Settings.Canvas.HighlighterWidth / 2;
+ drawingAttributes.Height = Settings.Canvas.HighlighterWidth;
+ }
ColorSwitchCheck();
HideSubPanels("pen", true);
@@ -1918,10 +1958,9 @@ namespace Ink_Canvas
inkCanvas.EditingMode = InkCanvasEditingMode.EraseByStroke;
drawingShapeMode = 0;
- // 修复:切换到线擦时,确保重置笔的状态
- penType = 0;
- drawingAttributes.IsHighlighter = false;
- drawingAttributes.StylusTip = StylusTip.Ellipse;
+ // 修复:切换到线擦时,保存当前的笔类型状态,而不是强制重置
+ // 这样从线擦切换回批注时,可以恢复之前的荧光笔状态
+ // penType 和 drawingAttributes 的状态将在 PenIcon_Click 中根据 wasHighlighter 来恢复
inkCanvas_EditingModeChanged(inkCanvas, null);
CancelSingleFingerDragMode();
From 8719677f11f76915a04501b1a1703b60db6c23cf Mon Sep 17 00:00:00 2001
From: CJKmkp <2564608840@qq.com>
Date: Sat, 23 Aug 2025 18:55:36 +0800
Subject: [PATCH 19/45] =?UTF-8?q?fix:=E5=BC=80=E5=90=AF=E9=83=A8=E5=88=86?=
=?UTF-8?q?=E5=8A=9F=E8=83=BD=E5=90=8E=E6=89=8B=E5=8A=BF=E9=9D=A2=E6=9D=BF?=
=?UTF-8?q?=E6=98=BE=E7=A4=BA=E5=BC=82=E5=B8=B8?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Ink Canvas/MainWindow_cs/MW_Colors.cs | 4 ++++
Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs | 8 ++++++++
Ink Canvas/MainWindow_cs/MW_PPT.cs | 11 +++++++++++
3 files changed, 23 insertions(+)
diff --git a/Ink Canvas/MainWindow_cs/MW_Colors.cs b/Ink Canvas/MainWindow_cs/MW_Colors.cs
index 4c003865..fdd0b1ea 100644
--- a/Ink Canvas/MainWindow_cs/MW_Colors.cs
+++ b/Ink Canvas/MainWindow_cs/MW_Colors.cs
@@ -28,6 +28,10 @@ namespace Ink_Canvas
AnimationsHelper.HideWithSlideAndFade(BlackboardLeftSide);
AnimationsHelper.HideWithSlideAndFade(BlackboardCenterSide);
AnimationsHelper.HideWithSlideAndFade(BlackboardRightSide);
+
+ // 在PPT模式下隐藏手势面板
+ AnimationsHelper.HideWithSlideAndFade(TwoFingerGestureBorder);
+ AnimationsHelper.HideWithSlideAndFade(BoardTwoFingerGestureBorder);
}
BtnHideInkCanvas_Click(BtnHideInkCanvas, null);
diff --git a/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs b/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs
index eae5db73..0a17d259 100644
--- a/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs
+++ b/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs
@@ -2472,6 +2472,10 @@ namespace Ink_Canvas
DeselectUIElement();
+ // 在PPT模式下隐藏手势面板
+ AnimationsHelper.HideWithSlideAndFade(TwoFingerGestureBorder);
+ AnimationsHelper.HideWithSlideAndFade(BoardTwoFingerGestureBorder);
+
SaveStrokes(true);
ClearStrokes(true);
RestoreStrokes(true);
@@ -2517,6 +2521,10 @@ namespace Ink_Canvas
// 取消任何UI元素的选择
DeselectUIElement();
+ // 在PPT模式下隐藏手势面板
+ AnimationsHelper.HideWithSlideAndFade(TwoFingerGestureBorder);
+ AnimationsHelper.HideWithSlideAndFade(BoardTwoFingerGestureBorder);
+
SaveStrokes();
ClearStrokes(true);
RestoreStrokes(true);
diff --git a/Ink Canvas/MainWindow_cs/MW_PPT.cs b/Ink Canvas/MainWindow_cs/MW_PPT.cs
index 452f3f8b..50cf5edf 100644
--- a/Ink Canvas/MainWindow_cs/MW_PPT.cs
+++ b/Ink Canvas/MainWindow_cs/MW_PPT.cs
@@ -292,6 +292,10 @@ namespace Ink_Canvas
BorderFloatingBarMainControls.Visibility = Visibility.Visible;
+ // 在PPT模式下隐藏手势面板
+ AnimationsHelper.HideWithSlideAndFade(TwoFingerGestureBorder);
+ AnimationsHelper.HideWithSlideAndFade(BoardTwoFingerGestureBorder);
+
if (Settings.PowerPointSettings.IsShowCanvasAtNewSlideShow &&
!Settings.Automation.IsAutoFoldInPPTSlideShow)
BtnColorRed_Click(null, null);
@@ -394,6 +398,13 @@ namespace Ink_Canvas
// 注意:这里只清空索引0的备份,不影响白板页面的墨迹(索引1及以上)
TimeMachineHistories[0] = null;
+ // 退出PPT模式时恢复手势面板的显示状态
+ if (Settings.Gesture.IsEnableTwoFingerGesture && ToggleSwitchEnableMultiTouchMode.IsOn)
+ {
+ // 根据手势设置决定是否显示手势面板
+ CheckEnableTwoFingerGestureBtnVisibility(true);
+ }
+
if (GridTransparencyFakeBackground.Background != Brushes.Transparent)
BtnHideInkCanvas_Click(BtnHideInkCanvas, null);
}
From a5eb1dfca7331010927c3d7108b437bd48eab612 Mon Sep 17 00:00:00 2001
From: CJKmkp <2564608840@qq.com>
Date: Sat, 23 Aug 2025 18:58:57 +0800
Subject: [PATCH 20/45] =?UTF-8?q?fix:=E5=BC=80=E5=90=AF=E9=83=A8=E5=88=86?=
=?UTF-8?q?=E5=8A=9F=E8=83=BD=E5=90=8E=E6=89=8B=E5=8A=BF=E9=9D=A2=E6=9D=BF?=
=?UTF-8?q?=E6=98=BE=E7=A4=BA=E5=BC=82=E5=B8=B8?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Ink Canvas/MainWindow_cs/MW_Colors.cs | 3 ++-
Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs | 17 ++++++++++++-----
Ink Canvas/MainWindow_cs/MW_PPT.cs | 12 +++++++++---
3 files changed, 23 insertions(+), 9 deletions(-)
diff --git a/Ink Canvas/MainWindow_cs/MW_Colors.cs b/Ink Canvas/MainWindow_cs/MW_Colors.cs
index fdd0b1ea..baa50911 100644
--- a/Ink Canvas/MainWindow_cs/MW_Colors.cs
+++ b/Ink Canvas/MainWindow_cs/MW_Colors.cs
@@ -29,9 +29,10 @@ namespace Ink_Canvas
AnimationsHelper.HideWithSlideAndFade(BlackboardCenterSide);
AnimationsHelper.HideWithSlideAndFade(BlackboardRightSide);
- // 在PPT模式下隐藏手势面板
+ // 在PPT模式下隐藏手势面板和手势按钮
AnimationsHelper.HideWithSlideAndFade(TwoFingerGestureBorder);
AnimationsHelper.HideWithSlideAndFade(BoardTwoFingerGestureBorder);
+ EnableTwoFingerGestureBorder.Visibility = Visibility.Collapsed;
}
BtnHideInkCanvas_Click(BtnHideInkCanvas, null);
diff --git a/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs b/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs
index 0a17d259..edd67c3d 100644
--- a/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs
+++ b/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs
@@ -124,6 +124,13 @@ namespace Ink_Canvas
///
private void CheckEnableTwoFingerGestureBtnVisibility(bool isVisible)
{
+ // 在PPT模式下始终隐藏手势按钮
+ if (currentMode == 0 || BtnPPTSlideShowEnd.Visibility == Visibility.Visible)
+ {
+ EnableTwoFingerGestureBorder.Visibility = Visibility.Collapsed;
+ return;
+ }
+
if (StackPanelCanvasControls.Visibility != Visibility.Visible
|| BorderFloatingBarMainControls.Visibility != Visibility.Visible)
{
@@ -131,9 +138,7 @@ namespace Ink_Canvas
}
else if (isVisible)
{
- if (BtnPPTSlideShowEnd.Visibility == Visibility.Visible)
- EnableTwoFingerGestureBorder.Visibility = Visibility.Collapsed;
- else EnableTwoFingerGestureBorder.Visibility = Visibility.Visible;
+ EnableTwoFingerGestureBorder.Visibility = Visibility.Visible;
}
else
{
@@ -2472,9 +2477,10 @@ namespace Ink_Canvas
DeselectUIElement();
- // 在PPT模式下隐藏手势面板
+ // 在PPT模式下隐藏手势面板和手势按钮
AnimationsHelper.HideWithSlideAndFade(TwoFingerGestureBorder);
AnimationsHelper.HideWithSlideAndFade(BoardTwoFingerGestureBorder);
+ EnableTwoFingerGestureBorder.Visibility = Visibility.Collapsed;
SaveStrokes(true);
ClearStrokes(true);
@@ -2521,9 +2527,10 @@ namespace Ink_Canvas
// 取消任何UI元素的选择
DeselectUIElement();
- // 在PPT模式下隐藏手势面板
+ // 在PPT模式下隐藏手势面板和手势按钮
AnimationsHelper.HideWithSlideAndFade(TwoFingerGestureBorder);
AnimationsHelper.HideWithSlideAndFade(BoardTwoFingerGestureBorder);
+ EnableTwoFingerGestureBorder.Visibility = Visibility.Collapsed;
SaveStrokes();
ClearStrokes(true);
diff --git a/Ink Canvas/MainWindow_cs/MW_PPT.cs b/Ink Canvas/MainWindow_cs/MW_PPT.cs
index 50cf5edf..384f86c3 100644
--- a/Ink Canvas/MainWindow_cs/MW_PPT.cs
+++ b/Ink Canvas/MainWindow_cs/MW_PPT.cs
@@ -292,9 +292,10 @@ namespace Ink_Canvas
BorderFloatingBarMainControls.Visibility = Visibility.Visible;
- // 在PPT模式下隐藏手势面板
+ // 在PPT模式下隐藏手势面板和手势按钮
AnimationsHelper.HideWithSlideAndFade(TwoFingerGestureBorder);
AnimationsHelper.HideWithSlideAndFade(BoardTwoFingerGestureBorder);
+ EnableTwoFingerGestureBorder.Visibility = Visibility.Collapsed;
if (Settings.PowerPointSettings.IsShowCanvasAtNewSlideShow &&
!Settings.Automation.IsAutoFoldInPPTSlideShow)
@@ -398,12 +399,17 @@ namespace Ink_Canvas
// 注意:这里只清空索引0的备份,不影响白板页面的墨迹(索引1及以上)
TimeMachineHistories[0] = null;
- // 退出PPT模式时恢复手势面板的显示状态
+ // 退出PPT模式时恢复手势面板和手势按钮的显示状态
if (Settings.Gesture.IsEnableTwoFingerGesture && ToggleSwitchEnableMultiTouchMode.IsOn)
{
- // 根据手势设置决定是否显示手势面板
+ // 根据手势设置决定是否显示手势面板和手势按钮
CheckEnableTwoFingerGestureBtnVisibility(true);
}
+ else
+ {
+ // 如果手势功能未启用,确保手势按钮保持隐藏
+ EnableTwoFingerGestureBorder.Visibility = Visibility.Collapsed;
+ }
if (GridTransparencyFakeBackground.Background != Brushes.Transparent)
BtnHideInkCanvas_Click(BtnHideInkCanvas, null);
From 40eeb9db66f4dd29a60c3f49f25007e9baef7187 Mon Sep 17 00:00:00 2001
From: CJKmkp <2564608840@qq.com>
Date: Sat, 23 Aug 2025 19:04:46 +0800
Subject: [PATCH 21/45] =?UTF-8?q?fix:=E9=80=80=E5=87=BA=E6=94=BE=E6=98=A0?=
=?UTF-8?q?=E6=A8=A1=E5=BC=8F=E5=90=8E=E6=B5=AE=E5=8A=A8=E6=A0=8F=E5=BC=82?=
=?UTF-8?q?=E5=B8=B8=E9=97=AE=E9=A2=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Ink Canvas/MainWindow_cs/MW_PPT.cs | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/Ink Canvas/MainWindow_cs/MW_PPT.cs b/Ink Canvas/MainWindow_cs/MW_PPT.cs
index 384f86c3..07b2abcc 100644
--- a/Ink Canvas/MainWindow_cs/MW_PPT.cs
+++ b/Ink Canvas/MainWindow_cs/MW_PPT.cs
@@ -411,6 +411,16 @@ namespace Ink_Canvas
EnableTwoFingerGestureBorder.Visibility = Visibility.Collapsed;
}
+ // 退出PPT模式时隐藏快捷调色盘
+ if (QuickColorPalettePanel != null)
+ {
+ QuickColorPalettePanel.Visibility = Visibility.Collapsed;
+ }
+ if (QuickColorPaletteSingleRowPanel != null)
+ {
+ QuickColorPaletteSingleRowPanel.Visibility = Visibility.Collapsed;
+ }
+
if (GridTransparencyFakeBackground.Background != Brushes.Transparent)
BtnHideInkCanvas_Click(BtnHideInkCanvas, null);
}
@@ -423,6 +433,9 @@ namespace Ink_Canvas
await Task.Delay(150);
await Application.Current.Dispatcher.InvokeAsync(() =>
{
+ // 强制重新计算浮动栏位置,确保在退出PPT模式后正确复位
+ // 先调用桌面模式的复位方法,然后调用通用的位置计算方法
+ PureViewboxFloatingBarMarginAnimationInDesktopMode();
ViewboxFloatingBarMarginAnimation(100, true);
});
}
From 44278d68b4e791abcc84cc1eec055aff4b363779 Mon Sep 17 00:00:00 2001
From: CJKmkp <2564608840@qq.com>
Date: Sat, 23 Aug 2025 19:10:53 +0800
Subject: [PATCH 22/45] =?UTF-8?q?fix:=E7=BF=BB=E9=A1=B5=E6=8E=A7=E4=BB=B6?=
=?UTF-8?q?=E4=B8=8D=E5=90=88=E7=90=86=E7=9A=84=E6=98=BE=E7=A4=BA=E6=97=B6?=
=?UTF-8?q?=E6=9C=BA?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Ink Canvas/Helpers/PPTManager.cs | 46 ++++++++++++++++++++++++++++++
Ink Canvas/Helpers/PPTUIManager.cs | 29 ++++++++++++++++++-
Ink Canvas/MainWindow_cs/MW_PPT.cs | 27 ++++++++++++++++++
3 files changed, 101 insertions(+), 1 deletion(-)
diff --git a/Ink Canvas/Helpers/PPTManager.cs b/Ink Canvas/Helpers/PPTManager.cs
index 1a2d5a90..c51fa589 100644
--- a/Ink Canvas/Helpers/PPTManager.cs
+++ b/Ink Canvas/Helpers/PPTManager.cs
@@ -25,6 +25,7 @@ namespace Ink_Canvas.Helpers
public event Action PresentationOpen;
public event Action PresentationClose;
public event Action PPTConnectionChanged;
+ public event Action SlideShowStateChanged;
#endregion
#region Properties
@@ -92,6 +93,7 @@ namespace Ink_Canvas.Helpers
#region Private Fields
private Timer _connectionCheckTimer;
+ private Timer _slideShowStateCheckTimer;
private Timer _wpsProcessCheckTimer;
private Process _wpsProcess;
private bool _hasWpsProcessId;
@@ -99,6 +101,7 @@ namespace Ink_Canvas.Helpers
private int _wpsProcessCheckCount;
private WpsWindowInfo _lastForegroundWpsWindow;
private DateTime _lastWindowCheckTime = DateTime.MinValue;
+ private bool _lastSlideShowState = false;
private readonly object _lockObject = new object();
private bool _disposed = false;
#endregion
@@ -114,6 +117,10 @@ namespace Ink_Canvas.Helpers
_connectionCheckTimer = new Timer(500);
_connectionCheckTimer.Elapsed += OnConnectionCheckTimerElapsed;
_connectionCheckTimer.AutoReset = true;
+
+ _slideShowStateCheckTimer = new Timer(1000);
+ _slideShowStateCheckTimer.Elapsed += OnSlideShowStateCheckTimerElapsed;
+ _slideShowStateCheckTimer.AutoReset = true;
}
public void StartMonitoring()
@@ -121,6 +128,7 @@ namespace Ink_Canvas.Helpers
if (!_disposed)
{
_connectionCheckTimer?.Start();
+ _slideShowStateCheckTimer?.Start();
LogHelper.WriteLogToFile("PPT监控已启动", LogHelper.LogType.Trace);
}
}
@@ -128,6 +136,7 @@ namespace Ink_Canvas.Helpers
public void StopMonitoring()
{
_connectionCheckTimer?.Stop();
+ _slideShowStateCheckTimer?.Stop();
DisconnectFromPPT();
LogHelper.WriteLogToFile("PPT监控已停止", LogHelper.LogType.Trace);
}
@@ -146,6 +155,18 @@ namespace Ink_Canvas.Helpers
}
}
+ private void OnSlideShowStateCheckTimerElapsed(object sender, ElapsedEventArgs e)
+ {
+ try
+ {
+ CheckSlideShowState();
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"PPT放映状态检查失败: {ex}", LogHelper.LogType.Error);
+ }
+ }
+
private void CheckAndConnectToPPT()
{
lock (_lockObject)
@@ -187,6 +208,30 @@ namespace Ink_Canvas.Helpers
}
}
+ private void CheckSlideShowState()
+ {
+ try
+ {
+ if (!IsConnected) return;
+
+ var currentSlideShowState = IsInSlideShow;
+ if (currentSlideShowState != _lastSlideShowState)
+ {
+ _lastSlideShowState = currentSlideShowState;
+ SlideShowStateChanged?.Invoke(currentSlideShowState);
+
+ if (!currentSlideShowState)
+ {
+ LogHelper.WriteLogToFile("检测到PPT放映已结束", LogHelper.LogType.Trace);
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"检查PPT放映状态异常: {ex}", LogHelper.LogType.Error);
+ }
+ }
+
private Microsoft.Office.Interop.PowerPoint.Application TryConnectToPowerPoint()
{
try
@@ -1627,6 +1672,7 @@ namespace Ink_Canvas.Helpers
StopWpsProcessCheckTimer();
_connectionCheckTimer?.Dispose();
+ _slideShowStateCheckTimer?.Dispose();
_wpsProcessCheckTimer?.Dispose();
_disposed = true;
diff --git a/Ink Canvas/Helpers/PPTUIManager.cs b/Ink Canvas/Helpers/PPTUIManager.cs
index ca235958..fd2f5add 100644
--- a/Ink Canvas/Helpers/PPTUIManager.cs
+++ b/Ink Canvas/Helpers/PPTUIManager.cs
@@ -3,6 +3,7 @@ using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Threading;
+using Ink_Canvas.Helpers;
namespace Ink_Canvas.Helpers
{
@@ -120,6 +121,29 @@ namespace Ink_Canvas.Helpers
});
}
+ ///
+ /// 处理PPT放映状态变化
+ ///
+ public void OnSlideShowStateChanged(bool isInSlideShow)
+ {
+ _dispatcher.InvokeAsync(() =>
+ {
+ try
+ {
+ if (!isInSlideShow)
+ {
+ // 如果不在放映模式,隐藏所有导航面板
+ HideAllNavigationPanels();
+ LogHelper.WriteLogToFile("PPT放映状态变化:隐藏导航面板", LogHelper.LogType.Trace);
+ }
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"处理PPT放映状态变化失败: {ex}", LogHelper.LogType.Error);
+ }
+ });
+ }
+
///
/// 更新导航面板显示状态
///
@@ -130,7 +154,10 @@ namespace Ink_Canvas.Helpers
try
{
// 检查是否应该显示PPT按钮
- bool shouldShowButtons = ShowPPTButton && _mainWindow.BtnPPTSlideShowEnd.Visibility == Visibility.Visible;
+ // 不仅要检查按钮设置,还要确保确实在PPT放映模式下
+ bool shouldShowButtons = ShowPPTButton &&
+ _mainWindow.BtnPPTSlideShowEnd.Visibility == Visibility.Visible &&
+ _mainWindow.PPTManager?.IsInSlideShow == true;
if (!shouldShowButtons)
{
diff --git a/Ink Canvas/MainWindow_cs/MW_PPT.cs b/Ink Canvas/MainWindow_cs/MW_PPT.cs
index 07b2abcc..8753f03b 100644
--- a/Ink Canvas/MainWindow_cs/MW_PPT.cs
+++ b/Ink Canvas/MainWindow_cs/MW_PPT.cs
@@ -86,6 +86,11 @@ namespace Ink_Canvas
private PPTManager _pptManager;
private PPTInkManager _pptInkManager;
private PPTUIManager _pptUIManager;
+
+ ///
+ /// 获取PPT管理器实例(供UI管理器使用)
+ ///
+ public PPTManager PPTManager => _pptManager;
#endregion
#region PPT Manager Initialization
@@ -104,6 +109,7 @@ namespace Ink_Canvas
_pptManager.SlideShowEnd += OnPPTSlideShowEnd;
_pptManager.PresentationOpen += OnPPTPresentationOpen;
_pptManager.PresentationClose += OnPPTPresentationClose;
+ _pptManager.SlideShowStateChanged += OnPPTSlideShowStateChanged;
// 初始化墨迹管理器
_pptInkManager = new PPTInkManager();
@@ -242,6 +248,27 @@ namespace Ink_Canvas
}
}
+ private void OnPPTSlideShowStateChanged(bool isInSlideShow)
+ {
+ try
+ {
+ Application.Current.Dispatcher.InvokeAsync(() =>
+ {
+ // 通知UI管理器放映状态变化
+ _pptUIManager?.OnSlideShowStateChanged(isInSlideShow);
+
+ if (!isInSlideShow)
+ {
+ LogHelper.WriteLogToFile("PPT放映状态变化:退出放映模式", LogHelper.LogType.Trace);
+ }
+ });
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"处理PPT放映状态变化失败: {ex}", LogHelper.LogType.Error);
+ }
+ }
+
private async void OnPPTSlideShowBegin(SlideShowWindow wn)
{
try
From 15082c2c52eab3ba779aa1d85e1d81341528ec81 Mon Sep 17 00:00:00 2001
From: CJKmkp <2564608840@qq.com>
Date: Sat, 23 Aug 2025 19:16:19 +0800
Subject: [PATCH 23/45] =?UTF-8?q?fix:=E5=A2=A8=E8=BF=B9=E5=87=BA=E7=8E=B0?=
=?UTF-8?q?=E5=9C=A8=E4=B8=8D=E5=AF=B9=E5=BA=94=E7=9A=84PPT=E6=96=87?=
=?UTF-8?q?=E6=A1=A3=E4=B8=8A?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Ink Canvas/Helpers/PPTInkManager.cs | 24 +++++++++++++++++++++---
Ink Canvas/MainWindow_cs/MW_PPT.cs | 11 +++++++++++
2 files changed, 32 insertions(+), 3 deletions(-)
diff --git a/Ink Canvas/Helpers/PPTInkManager.cs b/Ink Canvas/Helpers/PPTInkManager.cs
index 0c548829..f8c62ccb 100644
--- a/Ink Canvas/Helpers/PPTInkManager.cs
+++ b/Ink Canvas/Helpers/PPTInkManager.cs
@@ -55,6 +55,13 @@ namespace Ink_Canvas.Helpers
{
try
{
+ // 完全清理之前的墨迹状态
+ ClearAllStrokes();
+
+ // 重置墨迹锁定状态
+ _inkLockUntil = DateTime.MinValue;
+ _lockedSlideIndex = -1;
+
// 生成演示文稿唯一标识符
_currentPresentationId = GeneratePresentationId(presentation);
@@ -152,17 +159,28 @@ namespace Ink_Canvas.Helpers
{
try
{
- // 如果有当前墨迹,先保存
+ // 如果有当前墨迹,先保存到正确的页面
if (currentStrokes != null && currentStrokes.Count > 0)
{
- SaveCurrentSlideStrokes(_lockedSlideIndex > 0 ? _lockedSlideIndex : slideIndex, currentStrokes);
+ // 确定要保存的页面索引
+ int saveToSlideIndex = _lockedSlideIndex > 0 ? _lockedSlideIndex : slideIndex;
+
+ // 确保页面索引有效
+ if (saveToSlideIndex > 0 && saveToSlideIndex < _memoryStreams.Length)
+ {
+ SaveCurrentSlideStrokes(saveToSlideIndex, currentStrokes);
+ LogHelper.WriteLogToFile($"已保存第{saveToSlideIndex}页墨迹,墨迹数量: {currentStrokes.Count}", LogHelper.LogType.Trace);
+ }
}
// 设置墨迹锁定
LockInkForSlide(slideIndex);
// 加载新页面的墨迹
- return LoadSlideStrokes(slideIndex);
+ var newStrokes = LoadSlideStrokes(slideIndex);
+ LogHelper.WriteLogToFile($"已切换到第{slideIndex}页,加载墨迹数量: {newStrokes.Count}", LogHelper.LogType.Trace);
+
+ return newStrokes;
}
catch (Exception ex)
{
diff --git a/Ink Canvas/MainWindow_cs/MW_PPT.cs b/Ink Canvas/MainWindow_cs/MW_PPT.cs
index 8753f03b..9ccf8b6b 100644
--- a/Ink Canvas/MainWindow_cs/MW_PPT.cs
+++ b/Ink Canvas/MainWindow_cs/MW_PPT.cs
@@ -200,6 +200,15 @@ namespace Ink_Canvas
{
Application.Current.Dispatcher.InvokeAsync(() =>
{
+ // 在初始化墨迹管理器之前,先清理画布上的所有墨迹
+ ClearStrokes(true);
+
+ // 清理备份历史记录,防止旧演示文稿的墨迹影响新演示文稿
+ if (TimeMachineHistories != null && TimeMachineHistories.Length > 0)
+ {
+ TimeMachineHistories[0] = null;
+ }
+
// 初始化墨迹管理器
_pptInkManager?.InitializePresentation(pres);
@@ -219,6 +228,8 @@ namespace Ink_Canvas
}
_pptUIManager?.UpdateConnectionStatus(true);
+
+ LogHelper.WriteLogToFile($"已打开新演示文稿: {pres.Name},墨迹状态已清理", LogHelper.LogType.Event);
});
}
catch (Exception ex)
From ec2d5043ffa4cb361060c5a70af83a9bdccb0ff5 Mon Sep 17 00:00:00 2001
From: CJKmkp <2564608840@qq.com>
Date: Sat, 23 Aug 2025 19:27:30 +0800
Subject: [PATCH 24/45] =?UTF-8?q?add:=E5=BA=95=E9=83=A8PPT=E7=BF=BB?=
=?UTF-8?q?=E9=A1=B5=E6=8C=89=E9=92=AE=E8=B0=83=E8=8A=82?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Ink Canvas/Helpers/PPTUIManager.cs | 6 +
Ink Canvas/MainWindow.xaml | 155 ++++++++++++++++++
Ink Canvas/MainWindow_cs/MW_PPT.cs | 2 +
Ink Canvas/MainWindow_cs/MW_Settings.cs | 152 +++++++++++++++++
Ink Canvas/MainWindow_cs/MW_SettingsToLoad.cs | 4 +
Ink Canvas/Resources/Settings.cs | 8 +
6 files changed, 327 insertions(+)
diff --git a/Ink Canvas/Helpers/PPTUIManager.cs b/Ink Canvas/Helpers/PPTUIManager.cs
index fd2f5add..dfb4d353 100644
--- a/Ink Canvas/Helpers/PPTUIManager.cs
+++ b/Ink Canvas/Helpers/PPTUIManager.cs
@@ -19,6 +19,8 @@ namespace Ink_Canvas.Helpers
public int PPTBButtonsOption { get; set; } = 121;
public int PPTLSButtonPosition { get; set; } = 0;
public int PPTRSButtonPosition { get; set; } = 0;
+ public int PPTLBButtonPosition { get; set; } = 0;
+ public int PPTRBButtonPosition { get; set; } = 0;
public bool EnablePPTButtonPageClickable { get; set; } = true;
#endregion
@@ -169,6 +171,10 @@ namespace Ink_Canvas.Helpers
_mainWindow.LeftSidePanelForPPTNavigation.Margin = new Thickness(0, 0, 0, PPTLSButtonPosition * 2);
_mainWindow.RightSidePanelForPPTNavigation.Margin = new Thickness(0, 0, 0, PPTRSButtonPosition * 2);
+ // 设置底部按钮水平位置
+ _mainWindow.LeftBottomPanelForPPTNavigation.Margin = new Thickness(6 + PPTLBButtonPosition, 0, 0, 6);
+ _mainWindow.RightBottomPanelForPPTNavigation.Margin = new Thickness(0, 0, 6 + PPTRBButtonPosition, 6);
+
// 根据显示选项设置面板可见性
var displayOption = PPTButtonsDisplayOption.ToString();
if (displayOption.Length >= 4)
diff --git a/Ink Canvas/MainWindow.xaml b/Ink Canvas/MainWindow.xaml
index ae433f8f..96397e85 100644
--- a/Ink Canvas/MainWindow.xaml
+++ b/Ink Canvas/MainWindow.xaml
@@ -1618,6 +1618,161 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
= 500)
+ {
+ if (PPTButtonLBPositionValueSlider.Value >= 500)
+ {
+ PPTBtnLBPlusBtn.IsEnabled = false;
+ PPTBtnLBPlusBtn.Opacity = 0.5;
+ PPTButtonLBPositionValueSlider.Value = 500;
+ }
+ else if (PPTButtonLBPositionValueSlider.Value <= -500)
+ {
+ PPTBtnLBMinusBtn.IsEnabled = false;
+ PPTBtnLBMinusBtn.Opacity = 0.5;
+ PPTButtonLBPositionValueSlider.Value = -500;
+ }
+ }
+ else
+ {
+ PPTBtnLBPlusBtn.IsEnabled = true;
+ PPTBtnLBPlusBtn.Opacity = 1;
+ PPTBtnLBMinusBtn.IsEnabled = true;
+ PPTBtnLBMinusBtn.Opacity = 1;
+ }
+
+ if (PPTButtonRBPositionValueSlider.Value <= -500 || PPTButtonRBPositionValueSlider.Value >= 500)
+ {
+ if (PPTButtonRBPositionValueSlider.Value >= 500)
+ {
+ PPTBtnRBPlusBtn.IsEnabled = false;
+ PPTBtnRBPlusBtn.Opacity = 0.5;
+ PPTButtonRBPositionValueSlider.Value = 500;
+ }
+ else if (PPTButtonRBPositionValueSlider.Value <= -500)
+ {
+ PPTBtnRBMinusBtn.IsEnabled = false;
+ PPTBtnRBMinusBtn.Opacity = 0.5;
+ PPTButtonRBPositionValueSlider.Value = -500;
+ }
+ }
+ else
+ {
+ PPTBtnRBPlusBtn.IsEnabled = true;
+ PPTBtnRBPlusBtn.Opacity = 1;
+ PPTBtnRBMinusBtn.IsEnabled = true;
+ PPTBtnRBMinusBtn.Opacity = 1;
+ }
}
private void PPTBtnLSPlusBtn_Clicked(object sender, RoutedEventArgs e)
@@ -834,6 +881,8 @@ namespace Ink_Canvas
_pptUIManager.PPTBButtonsOption = Settings.PowerPointSettings.PPTBButtonsOption;
_pptUIManager.PPTLSButtonPosition = Settings.PowerPointSettings.PPTLSButtonPosition;
_pptUIManager.PPTRSButtonPosition = Settings.PowerPointSettings.PPTRSButtonPosition;
+ _pptUIManager.PPTLBButtonPosition = Settings.PowerPointSettings.PPTLBButtonPosition;
+ _pptUIManager.PPTRBButtonPosition = Settings.PowerPointSettings.PPTRBButtonPosition;
_pptUIManager.UpdateNavigationPanelsVisibility();
_pptUIManager.UpdateNavigationButtonStyles();
}
@@ -2798,6 +2847,109 @@ namespace Ink_Canvas
SaveSettingsToFile();
}
+ #region 底部按钮水平位置控制
+
+ private void PPTButtonLBPositionValueSlider_ValueChanged(object sender, RoutedEventArgs e)
+ {
+ if (!isLoaded) return;
+ Settings.PowerPointSettings.PPTLBButtonPosition = (int)PPTButtonLBPositionValueSlider.Value;
+ UpdatePPTBtnSlidersStatus();
+ UpdatePPTUIManagerSettings();
+ SliderDelayAction.DebounceAction(2000, null, SaveSettingsToFile);
+ UpdatePPTBtnPreview();
+ }
+
+ private void PPTButtonRBPositionValueSlider_ValueChanged(object sender, RoutedEventArgs e)
+ {
+ if (!isLoaded) return;
+ Settings.PowerPointSettings.PPTRBButtonPosition = (int)PPTButtonRBPositionValueSlider.Value;
+ UpdatePPTBtnSlidersStatus();
+ UpdatePPTUIManagerSettings();
+ SliderDelayAction.DebounceAction(2000, null, SaveSettingsToFile);
+ UpdatePPTBtnPreview();
+ }
+
+ private void PPTBtnLBPlusBtn_Clicked(object sender, RoutedEventArgs e)
+ {
+ if (!isLoaded) return;
+ PPTButtonLBPositionValueSlider.Value++;
+ UpdatePPTBtnSlidersStatus();
+ Settings.PowerPointSettings.PPTLBButtonPosition = (int)PPTButtonLBPositionValueSlider.Value;
+ SaveSettingsToFile();
+ UpdatePPTBtnPreview();
+ }
+
+ private void PPTBtnLBMinusBtn_Clicked(object sender, RoutedEventArgs e)
+ {
+ if (!isLoaded) return;
+ PPTButtonLBPositionValueSlider.Value--;
+ UpdatePPTBtnSlidersStatus();
+ Settings.PowerPointSettings.PPTLBButtonPosition = (int)PPTButtonLBPositionValueSlider.Value;
+ SaveSettingsToFile();
+ UpdatePPTBtnPreview();
+ }
+
+ private void PPTBtnLBSyncBtn_Clicked(object sender, RoutedEventArgs e)
+ {
+ if (!isLoaded) return;
+ PPTButtonRBPositionValueSlider.Value = PPTButtonLBPositionValueSlider.Value;
+ UpdatePPTBtnSlidersStatus();
+ Settings.PowerPointSettings.PPTRBButtonPosition = (int)PPTButtonLBPositionValueSlider.Value;
+ SaveSettingsToFile();
+ UpdatePPTBtnPreview();
+ }
+
+ private void PPTBtnLBResetBtn_Clicked(object sender, RoutedEventArgs e)
+ {
+ if (!isLoaded) return;
+ PPTButtonLBPositionValueSlider.Value = 0;
+ UpdatePPTBtnSlidersStatus();
+ Settings.PowerPointSettings.PPTLBButtonPosition = 0;
+ SaveSettingsToFile();
+ UpdatePPTBtnPreview();
+ }
+
+ private void PPTBtnRBPlusBtn_Clicked(object sender, RoutedEventArgs e)
+ {
+ if (!isLoaded) return;
+ PPTButtonRBPositionValueSlider.Value++;
+ UpdatePPTBtnSlidersStatus();
+ Settings.PowerPointSettings.PPTRBButtonPosition = (int)PPTButtonRBPositionValueSlider.Value;
+ SaveSettingsToFile();
+ UpdatePPTBtnPreview();
+ }
+
+ private void PPTBtnRBMinusBtn_Clicked(object sender, RoutedEventArgs e)
+ {
+ if (!isLoaded) return;
+ PPTButtonRBPositionValueSlider.Value--;
+ UpdatePPTBtnSlidersStatus();
+ Settings.PowerPointSettings.PPTRBButtonPosition = (int)PPTButtonRBPositionValueSlider.Value;
+ SaveSettingsToFile();
+ UpdatePPTBtnPreview();
+ }
+
+ private void PPTBtnRBSyncBtn_Clicked(object sender, RoutedEventArgs e)
+ {
+ if (!isLoaded) return;
+ PPTButtonLBPositionValueSlider.Value = PPTButtonRBPositionValueSlider.Value;
+ UpdatePPTBtnSlidersStatus();
+ Settings.PowerPointSettings.PPTLBButtonPosition = (int)PPTButtonRBPositionValueSlider.Value;
+ SaveSettingsToFile();
+ UpdatePPTBtnPreview();
+ }
+
+ private void PPTBtnRBResetBtn_Clicked(object sender, RoutedEventArgs e)
+ {
+ if (!isLoaded) return;
+ PPTButtonRBPositionValueSlider.Value = 0;
+ Settings.PowerPointSettings.PPTRBButtonPosition = 0;
+ SaveSettingsToFile();
+ UpdatePPTBtnPreview();
+ }
+
+ #endregion
+
}
}
diff --git a/Ink Canvas/MainWindow_cs/MW_SettingsToLoad.cs b/Ink Canvas/MainWindow_cs/MW_SettingsToLoad.cs
index 77e50239..b350d73c 100644
--- a/Ink Canvas/MainWindow_cs/MW_SettingsToLoad.cs
+++ b/Ink Canvas/MainWindow_cs/MW_SettingsToLoad.cs
@@ -427,6 +427,10 @@ namespace Ink_Canvas
PPTButtonRightPositionValueSlider.Value = Settings.PowerPointSettings.PPTRSButtonPosition;
+ PPTButtonLBPositionValueSlider.Value = Settings.PowerPointSettings.PPTLBButtonPosition;
+
+ PPTButtonRBPositionValueSlider.Value = Settings.PowerPointSettings.PPTRBButtonPosition;
+
UpdatePPTBtnSlidersStatus();
UpdatePPTBtnPreview();
diff --git a/Ink Canvas/Resources/Settings.cs b/Ink Canvas/Resources/Settings.cs
index 3f7546bb..d5c7b5a0 100644
--- a/Ink Canvas/Resources/Settings.cs
+++ b/Ink Canvas/Resources/Settings.cs
@@ -245,6 +245,14 @@ namespace Ink_Canvas
[JsonProperty("pptRSButtonPosition")]
public int PPTRSButtonPosition { get; set; }
+ // 0居中,+就是往右,-就是往左
+ [JsonProperty("pptLBButtonPosition")]
+ public int PPTLBButtonPosition { get; set; }
+
+ // 0居中,+就是往右,-就是往左
+ [JsonProperty("pptRBButtonPosition")]
+ public int PPTRBButtonPosition { get; set; }
+
[JsonProperty("pptSButtonsOption")]
public int PPTSButtonsOption { get; set; } = 221;
From d01a24f87994a43a414875df9ab6f18eb88be469 Mon Sep 17 00:00:00 2001
From: CJKmkp <2564608840@qq.com>
Date: Sat, 23 Aug 2025 19:32:13 +0800
Subject: [PATCH 25/45] =?UTF-8?q?add:=E5=BA=95=E9=83=A8=E7=BF=BB=E9=A1=B5?=
=?UTF-8?q?=E6=8E=A7=E4=BB=B6=E9=A2=84=E8=A7=88?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Ink Canvas/MainWindow.xaml | 16 ++++++++++++++--
Ink Canvas/MainWindow_cs/MW_Settings.cs | 3 +++
2 files changed, 17 insertions(+), 2 deletions(-)
diff --git a/Ink Canvas/MainWindow.xaml b/Ink Canvas/MainWindow.xaml
index 96397e85..d6893bd0 100644
--- a/Ink Canvas/MainWindow.xaml
+++ b/Ink Canvas/MainWindow.xaml
@@ -1430,9 +1430,21 @@
+ VerticalAlignment="Bottom" HorizontalAlignment="Left" RenderTransformOrigin="0.5,0.5">
+
+
+
+
+
+
+ VerticalAlignment="Bottom" HorizontalAlignment="Right" RenderTransformOrigin="0.5,0.5">
+
+
+
+
+
+
diff --git a/Ink Canvas/MainWindow_cs/MW_Settings.cs b/Ink Canvas/MainWindow_cs/MW_Settings.cs
index 3b0061fb..d3a695fc 100644
--- a/Ink Canvas/MainWindow_cs/MW_Settings.cs
+++ b/Ink Canvas/MainWindow_cs/MW_Settings.cs
@@ -971,6 +971,9 @@ namespace Ink_Canvas
PPTBtnPreviewRSTransform.Y = -(Settings.PowerPointSettings.PPTRSButtonPosition * 0.5);
PPTBtnPreviewLSTransform.Y = -(Settings.PowerPointSettings.PPTLSButtonPosition * 0.5);
+
+ PPTBtnPreviewLBTransform.X = -(Settings.PowerPointSettings.PPTLBButtonPosition * 0.5);
+ PPTBtnPreviewRBTransform.X = -(Settings.PowerPointSettings.PPTRBButtonPosition * 0.5);
}
private void ToggleSwitchShowCursor_Toggled(object sender, RoutedEventArgs e)
From 70735943c304ae424435d4c2fa7d641b2d56a447 Mon Sep 17 00:00:00 2001
From: CJKmkp <2564608840@qq.com>
Date: Sat, 23 Aug 2025 19:43:09 +0800
Subject: [PATCH 26/45] =?UTF-8?q?add:=E9=95=BF=E6=8C=89=E7=BF=BB=E9=A1=B5?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Ink Canvas/Helpers/PPTUIManager.cs | 1 +
Ink Canvas/MainWindow.xaml | 13 +++
Ink Canvas/MainWindow_cs/MW_PPT.cs | 94 +++++++++++++++++++
Ink Canvas/MainWindow_cs/MW_Settings.cs | 9 ++
Ink Canvas/MainWindow_cs/MW_SettingsToLoad.cs | 3 +
Ink Canvas/Resources/Settings.cs | 3 +
6 files changed, 123 insertions(+)
diff --git a/Ink Canvas/Helpers/PPTUIManager.cs b/Ink Canvas/Helpers/PPTUIManager.cs
index dfb4d353..6fe95e2c 100644
--- a/Ink Canvas/Helpers/PPTUIManager.cs
+++ b/Ink Canvas/Helpers/PPTUIManager.cs
@@ -22,6 +22,7 @@ namespace Ink_Canvas.Helpers
public int PPTLBButtonPosition { get; set; } = 0;
public int PPTRBButtonPosition { get; set; } = 0;
public bool EnablePPTButtonPageClickable { get; set; } = true;
+ public bool EnablePPTButtonLongPressPageTurn { get; set; } = true;
#endregion
#region Private Fields
diff --git a/Ink Canvas/MainWindow.xaml b/Ink Canvas/MainWindow.xaml
index d6893bd0..9597d615 100644
--- a/Ink Canvas/MainWindow.xaml
+++ b/Ink Canvas/MainWindow.xaml
@@ -1843,6 +1843,19 @@
+
+
+
+
+
diff --git a/Ink Canvas/MainWindow_cs/MW_PPT.cs b/Ink Canvas/MainWindow_cs/MW_PPT.cs
index 3a5cd22d..4834a155 100644
--- a/Ink Canvas/MainWindow_cs/MW_PPT.cs
+++ b/Ink Canvas/MainWindow_cs/MW_PPT.cs
@@ -11,6 +11,7 @@ using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media;
+using System.Windows.Threading;
using Application = System.Windows.Application;
using File = System.IO.File;
using MessageBox = System.Windows.MessageBox;
@@ -80,6 +81,13 @@ namespace Ink_Canvas
private bool isPresentationHaveBlackSpace;
private string pptName;
private bool _isPptClickingBtnTurned;
+
+ // 长按翻页相关字段
+ private DispatcherTimer _longPressTimer;
+ private bool _isLongPressActive = false;
+ private bool _isLongPressNext = true; // true为下一页,false为上一页
+ private const int LongPressDelay = 500; // 长按延迟时间(毫秒)
+ private const int LongPressInterval = 200; // 长按翻页间隔(毫秒)
#endregion
#region PPT Managers
@@ -98,6 +106,9 @@ namespace Ink_Canvas
{
try
{
+ // 初始化长按定时器
+ InitializeLongPressTimer();
+
// 初始化PPT管理器
_pptManager = new PPTManager();
_pptManager.IsSupportWPS = Settings.PowerPointSettings.IsSupportWPS;
@@ -127,6 +138,7 @@ namespace Ink_Canvas
_pptUIManager.PPTLBButtonPosition = Settings.PowerPointSettings.PPTLBButtonPosition;
_pptUIManager.PPTRBButtonPosition = Settings.PowerPointSettings.PPTRBButtonPosition;
_pptUIManager.EnablePPTButtonPageClickable = Settings.PowerPointSettings.EnablePPTButtonPageClickable;
+ _pptUIManager.EnablePPTButtonLongPressPageTurn = Settings.PowerPointSettings.EnablePPTButtonLongPressPageTurn;
LogHelper.WriteLogToFile("PPT管理器初始化完成", LogHelper.LogType.Event);
}
@@ -157,6 +169,8 @@ namespace Ink_Canvas
{
_pptManager?.Dispose();
_pptInkManager?.Dispose();
+ _longPressTimer?.Stop();
+ _longPressTimer = null;
_pptManager = null;
_pptInkManager = null;
_pptUIManager = null;
@@ -167,6 +181,60 @@ namespace Ink_Canvas
LogHelper.WriteLogToFile($"释放PPT管理器失败: {ex}", LogHelper.LogType.Error);
}
}
+
+ ///
+ /// 初始化长按定时器
+ ///
+ private void InitializeLongPressTimer()
+ {
+ _longPressTimer = new DispatcherTimer();
+ _longPressTimer.Interval = TimeSpan.FromMilliseconds(LongPressDelay);
+ _longPressTimer.Tick += OnLongPressTimerTick;
+ }
+
+ ///
+ /// 启动长按检测
+ ///
+ /// 触发事件的控件
+ /// 是否为下一页按钮
+ private void StartLongPressDetection(object sender, bool isNext)
+ {
+ if (!Settings.PowerPointSettings.EnablePPTButtonLongPressPageTurn) return;
+
+ _isLongPressNext = isNext;
+ _isLongPressActive = false;
+ _longPressTimer?.Start();
+ }
+
+ ///
+ /// 停止长按检测
+ ///
+ private void StopLongPressDetection()
+ {
+ _longPressTimer?.Stop();
+ _isLongPressActive = false;
+ }
+
+ ///
+ /// 长按定时器事件处理
+ ///
+ private void OnLongPressTimerTick(object sender, EventArgs e)
+ {
+ if (!Settings.PowerPointSettings.EnablePPTButtonLongPressPageTurn) return;
+
+ _isLongPressActive = true;
+ _longPressTimer.Interval = TimeSpan.FromMilliseconds(LongPressInterval);
+
+ // 执行翻页
+ if (_isLongPressNext)
+ {
+ BtnPPTSlidesDown_Click(BtnPPTSlidesDown, null);
+ }
+ else
+ {
+ BtnPPTSlidesUp_Click(BtnPPTSlidesUp, null);
+ }
+ }
#endregion
#region New PPT Event Handlers
@@ -1047,6 +1115,12 @@ namespace Ink_Canvas
{
PPTRBPreviousButtonFeedbackBorder.Opacity = 0.15;
}
+
+ // 启动长按检测
+ if (Settings.PowerPointSettings.EnablePPTButtonLongPressPageTurn)
+ {
+ StartLongPressDetection(sender, false);
+ }
}
private void GridPPTControlPrevious_MouseLeave(object sender, MouseEventArgs e)
{
@@ -1067,6 +1141,9 @@ namespace Ink_Canvas
{
PPTRBPreviousButtonFeedbackBorder.Opacity = 0;
}
+
+ // 停止长按检测
+ StopLongPressDetection();
}
private void GridPPTControlPrevious_MouseUp(object sender, MouseButtonEventArgs e)
{
@@ -1087,6 +1164,10 @@ namespace Ink_Canvas
{
PPTRBPreviousButtonFeedbackBorder.Opacity = 0;
}
+
+ // 停止长按检测
+ StopLongPressDetection();
+
BtnPPTSlidesUp_Click(BtnPPTSlidesUp, null);
}
@@ -1110,6 +1191,12 @@ namespace Ink_Canvas
{
PPTRBNextButtonFeedbackBorder.Opacity = 0.15;
}
+
+ // 启动长按检测
+ if (Settings.PowerPointSettings.EnablePPTButtonLongPressPageTurn)
+ {
+ StartLongPressDetection(sender, true);
+ }
}
private void GridPPTControlNext_MouseLeave(object sender, MouseEventArgs e)
{
@@ -1130,6 +1217,9 @@ namespace Ink_Canvas
{
PPTRBNextButtonFeedbackBorder.Opacity = 0;
}
+
+ // 停止长按检测
+ StopLongPressDetection();
}
private void GridPPTControlNext_MouseUp(object sender, MouseButtonEventArgs e)
{
@@ -1150,6 +1240,10 @@ namespace Ink_Canvas
{
PPTRBNextButtonFeedbackBorder.Opacity = 0;
}
+
+ // 停止长按检测
+ StopLongPressDetection();
+
BtnPPTSlidesDown_Click(BtnPPTSlidesDown, null);
}
diff --git a/Ink Canvas/MainWindow_cs/MW_Settings.cs b/Ink Canvas/MainWindow_cs/MW_Settings.cs
index d3a695fc..011c9842 100644
--- a/Ink Canvas/MainWindow_cs/MW_Settings.cs
+++ b/Ink Canvas/MainWindow_cs/MW_Settings.cs
@@ -511,6 +511,13 @@ namespace Ink_Canvas
SaveSettingsToFile();
}
+ private void ToggleSwitchEnablePPTButtonLongPressPageTurn_OnToggled(object sender, RoutedEventArgs e)
+ {
+ if (!isLoaded) return;
+ Settings.PowerPointSettings.EnablePPTButtonLongPressPageTurn = ToggleSwitchEnablePPTButtonLongPressPageTurn.IsOn;
+ SaveSettingsToFile();
+ }
+
private void CheckboxEnableLBPPTButton_IsCheckChanged(object sender, RoutedEventArgs e)
{
if (!isLoaded) return;
@@ -883,6 +890,8 @@ namespace Ink_Canvas
_pptUIManager.PPTRSButtonPosition = Settings.PowerPointSettings.PPTRSButtonPosition;
_pptUIManager.PPTLBButtonPosition = Settings.PowerPointSettings.PPTLBButtonPosition;
_pptUIManager.PPTRBButtonPosition = Settings.PowerPointSettings.PPTRBButtonPosition;
+ _pptUIManager.EnablePPTButtonPageClickable = Settings.PowerPointSettings.EnablePPTButtonPageClickable;
+ _pptUIManager.EnablePPTButtonLongPressPageTurn = Settings.PowerPointSettings.EnablePPTButtonLongPressPageTurn;
_pptUIManager.UpdateNavigationPanelsVisibility();
_pptUIManager.UpdateNavigationButtonStyles();
}
diff --git a/Ink Canvas/MainWindow_cs/MW_SettingsToLoad.cs b/Ink Canvas/MainWindow_cs/MW_SettingsToLoad.cs
index b350d73c..454f45a1 100644
--- a/Ink Canvas/MainWindow_cs/MW_SettingsToLoad.cs
+++ b/Ink Canvas/MainWindow_cs/MW_SettingsToLoad.cs
@@ -367,6 +367,9 @@ namespace Ink_Canvas
ToggleSwitchEnablePPTButtonPageClickable.IsOn =
Settings.PowerPointSettings.EnablePPTButtonPageClickable;
+ ToggleSwitchEnablePPTButtonLongPressPageTurn.IsOn =
+ Settings.PowerPointSettings.EnablePPTButtonLongPressPageTurn;
+
var dops = Settings.PowerPointSettings.PPTButtonsDisplayOption.ToString();
var dopsc = dops.ToCharArray();
if ((dopsc[0] == '1' || dopsc[0] == '2') && (dopsc[1] == '1' || dopsc[1] == '2') &&
diff --git a/Ink Canvas/Resources/Settings.cs b/Ink Canvas/Resources/Settings.cs
index d5c7b5a0..a80971c5 100644
--- a/Ink Canvas/Resources/Settings.cs
+++ b/Ink Canvas/Resources/Settings.cs
@@ -262,6 +262,9 @@ namespace Ink_Canvas
[JsonProperty("enablePPTButtonPageClickable")]
public bool EnablePPTButtonPageClickable { get; set; } = true;
+ [JsonProperty("enablePPTButtonLongPressPageTurn")]
+ public bool EnablePPTButtonLongPressPageTurn { get; set; } = true;
+
// -- new --
[JsonProperty("powerPointSupport")]
From 108c6b2b17ac731e90ae0f74ae26df53359b6afb Mon Sep 17 00:00:00 2001
From: CJKmkp <2564608840@qq.com>
Date: Sat, 23 Aug 2025 20:24:48 +0800
Subject: [PATCH 27/45] =?UTF-8?q?improve:=E4=BD=BF=E7=94=A8=E6=95=B0?=
=?UTF-8?q?=E6=8D=AE=E4=BF=9D=E5=AD=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Ink Canvas/Helpers/DeviceIdentifier.cs | 306 +++++++++++++++++++++++--
1 file changed, 285 insertions(+), 21 deletions(-)
diff --git a/Ink Canvas/Helpers/DeviceIdentifier.cs b/Ink Canvas/Helpers/DeviceIdentifier.cs
index 5d1d9d67..79140029 100644
--- a/Ink Canvas/Helpers/DeviceIdentifier.cs
+++ b/Ink Canvas/Helpers/DeviceIdentifier.cs
@@ -7,6 +7,7 @@ using System.Linq;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;
+using System.Threading;
namespace Ink_Canvas.Helpers
{
@@ -2750,35 +2751,298 @@ namespace Ink_Canvas.Helpers
///
public static void SaveUsageStatsOnShutdown()
{
- lock (fileLock) // 确保线程安全
+ // 使用超时锁防止死锁
+ if (!Monitor.TryEnter(fileLock, TimeSpan.FromSeconds(30)))
+ {
+ LogHelper.WriteLogToFile("DeviceIdentifier | 关机保存超时,使用备用保存策略", LogHelper.LogType.Warning);
+ SaveUsageStatsOnShutdownFallback();
+ return;
+ }
+
+ try
+ {
+ LogHelper.WriteLogToFile("DeviceIdentifier | 开始关机时保存使用时间数据", LogHelper.LogType.Info);
+
+ // 1. 加载现有使用统计数据(多重恢复策略)
+ UsageStats stats = LoadUsageStatsWithFallback();
+ if (stats == null)
+ {
+ stats = new UsageStats { DeviceId = DeviceId };
+ LogHelper.WriteLogToFile("DeviceIdentifier | 创建新的使用统计数据", LogHelper.LogType.Info);
+ }
+
+ // 2. 计算本次会话时长(防止异常值)
+ TimeSpan sessionDuration = DateTime.Now - App.appStartTime;
+ long sessionSeconds = Math.Max(0, (long)sessionDuration.TotalSeconds);
+
+ // 防止异常大的会话时长(超过24小时)
+ if (sessionSeconds > 86400)
+ {
+ sessionSeconds = 86400;
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 会话时长异常,已限制为24小时: {sessionSeconds}秒", LogHelper.LogType.Warning);
+ }
+
+ // 3. 更新统计数据
+ stats.TotalUsageSeconds += sessionSeconds;
+ stats.LaunchCount++;
+ stats.AverageSessionSeconds = stats.TotalUsageSeconds / (double)Math.Max(1, stats.LaunchCount);
+ stats.LastLaunchTime = DateTime.Now;
+
+ // 更新数据哈希值
+ stats.UpdateDataHash();
+
+ // 4. 多重保存策略 - 确保数据不丢失
+ var saveResults = new List();
+
+ // 4.1 保存到所有文件位置
+ saveResults.Add(SaveUsageStatsToAllFileLocations(stats));
+
+ // 4.2 保存到所有注册表位置
+ saveResults.Add(SaveUsageStatsToAllRegistryLocations(stats));
+
+ // 4.3 保存到内存缓存(作为最后防线)
+ SaveUsageStatsToMemoryCache(stats);
+
+ // 4.4 强制刷新文件系统缓存
+ ForceFlushFileSystem();
+
+ // 4.5 验证保存结果
+ var verificationResult = VerifyDataSaveResults(stats, saveResults);
+
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 关机保存完成,验证结果: {verificationResult}", LogHelper.LogType.Info);
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 关机时保存使用时间数据失败: {ex.Message}", LogHelper.LogType.Error);
+
+ // 即使主保存失败,也要尝试备用保存
+ try
+ {
+ SaveUsageStatsOnShutdownFallback();
+ }
+ catch (Exception fallbackEx)
+ {
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 备用保存也失败: {fallbackEx.Message}", LogHelper.LogType.Error);
+ }
+ }
+ finally
+ {
+ Monitor.Exit(fileLock);
+ }
+ }
+
+ ///
+ /// 关机保存的备用策略
+ ///
+ private static void SaveUsageStatsOnShutdownFallback()
+ {
+ try
+ {
+ LogHelper.WriteLogToFile("DeviceIdentifier | 执行关机保存备用策略", LogHelper.LogType.Warning);
+
+ // 使用最基本的保存方式
+ var stats = new UsageStats { DeviceId = DeviceId };
+ stats.TotalUsageSeconds = 1; // 最小记录
+ stats.LaunchCount = 1;
+ stats.LastLaunchTime = DateTime.Now;
+
+ // 只保存到最可靠的位置
+ SaveUsageStatsToFile(BackupUsageStatsPath, stats);
+ SaveUsageStatsToRegistry(stats);
+
+ LogHelper.WriteLogToFile("DeviceIdentifier | 备用策略执行完成", LogHelper.LogType.Info);
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 备用策略执行失败: {ex.Message}", LogHelper.LogType.Error);
+ }
+ }
+
+ ///
+ /// 加载使用统计数据(带多重恢复策略)
+ ///
+ private static UsageStats LoadUsageStatsWithFallback()
+ {
+ try
+ {
+ // 1. 尝试从主文件加载
+ var stats = LoadUsageStats();
+ if (stats != null) return stats;
+
+ // 2. 尝试从备份文件加载
+ stats = LoadUsageStatsFromFile(BackupUsageStatsPath);
+ if (stats != null) return stats;
+
+ // 3. 尝试从其他备份位置加载
+ var backupPaths = new[] { SecondaryUsageBackupPath, TertiaryUsageBackupPath, QuaternaryUsageBackupPath };
+ foreach (var path in backupPaths)
+ {
+ stats = LoadUsageStatsFromFile(path);
+ if (stats != null) return stats;
+ }
+
+ // 4. 尝试从注册表恢复
+ stats = LoadUsageStatsFromRegistry();
+ if (stats != null) return stats;
+
+ return null;
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 多重恢复加载失败: {ex.Message}", LogHelper.LogType.Error);
+ return null;
+ }
+ }
+
+ ///
+ /// 保存使用统计到所有文件位置
+ ///
+ private static string SaveUsageStatsToAllFileLocations(UsageStats stats)
+ {
+ var results = new List();
+ var filePaths = new[]
+ {
+ UsageStatsFilePath,
+ BackupUsageStatsPath,
+ SecondaryUsageBackupPath,
+ TertiaryUsageBackupPath,
+ QuaternaryUsageBackupPath
+ };
+
+ foreach (var filePath in filePaths)
{
try
{
- // 1. 加载现有使用统计数据
- UsageStats stats = LoadUsageStats();
- if (stats == null)
- {
- stats = new UsageStats { DeviceId = DeviceId };
- }
-
- // 2. 计算本次会话时长
- TimeSpan sessionDuration = DateTime.Now - App.appStartTime;
- long sessionSeconds = (long)sessionDuration.TotalSeconds;
-
- // 3. 更新统计数据
- stats.TotalUsageSeconds += sessionSeconds;
- stats.LaunchCount++;
- stats.AverageSessionSeconds = stats.TotalUsageSeconds / (double)stats.LaunchCount;
- stats.LastLaunchTime = DateTime.Now;
-
- // 4. 保存到所有备份位置
- SaveUsageStatsToAllLocations(stats);
+ SaveUsageStatsToFile(filePath, stats);
+ results.Add($"✓ {Path.GetFileName(filePath)}");
}
catch (Exception ex)
{
- LogHelper.WriteLogToFile($"关机时保存使用时间数据失败: {ex.Message}", LogHelper.LogType.Error);
+ results.Add($"✗ {Path.GetFileName(filePath)}: {ex.Message}");
}
}
+
+ return string.Join("\n", results);
}
+
+ ///
+ /// 保存使用统计到所有注册表位置
+ ///
+ private static string SaveUsageStatsToAllRegistryLocations(UsageStats stats)
+ {
+ var results = new List();
+
+ try
+ {
+ // 主注册表位置
+ SaveUsageStatsToRegistry(stats);
+ results.Add("✓ 主注册表位置");
+ }
+ catch (Exception ex)
+ {
+ results.Add($"✗ 主注册表位置: {ex.Message}");
+ }
+
+ try
+ {
+ // 备用注册表位置
+ SaveUsageStatsToMultipleRegistryLocations(stats);
+ results.Add("✓ 备用注册表位置");
+ }
+ catch (Exception ex)
+ {
+ results.Add($"✗ 备用注册表位置: {ex.Message}");
+ }
+
+ return string.Join("\n", results);
+ }
+
+ ///
+ /// 保存使用统计到内存缓存
+ ///
+ private static void SaveUsageStatsToMemoryCache(UsageStats stats)
+ {
+ try
+ {
+ // 将数据保存到静态变量作为内存备份
+ _cachedUsageStats = stats;
+ LogHelper.WriteLogToFile("DeviceIdentifier | 数据已保存到内存缓存", LogHelper.LogType.Info);
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 保存到内存缓存失败: {ex.Message}", LogHelper.LogType.Error);
+ }
+ }
+
+ ///
+ /// 强制刷新文件系统缓存
+ ///
+ private static void ForceFlushFileSystem()
+ {
+ try
+ {
+ // 强制刷新所有相关目录
+ var directories = new[]
+ {
+ Path.GetDirectoryName(UsageStatsFilePath),
+ Path.GetDirectoryName(BackupUsageStatsPath),
+ Path.GetDirectoryName(SecondaryUsageBackupPath),
+ Path.GetDirectoryName(TertiaryUsageBackupPath),
+ Path.GetDirectoryName(QuaternaryUsageBackupPath)
+ };
+
+ foreach (var dir in directories.Where(d => !string.IsNullOrEmpty(d) && Directory.Exists(d)))
+ {
+ try
+ {
+ // 创建临时文件来强制刷新
+ var tempFile = Path.Combine(dir, ".flush.tmp");
+ File.WriteAllText(tempFile, DateTime.Now.ToString());
+ File.Delete(tempFile);
+ }
+ catch { /* 忽略刷新错误 */ }
+ }
+
+ LogHelper.WriteLogToFile("DeviceIdentifier | 文件系统缓存刷新完成", LogHelper.LogType.Info);
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"DeviceIdentifier | 文件系统缓存刷新失败: {ex.Message}", LogHelper.LogType.Error);
+ }
+ }
+
+ ///
+ /// 验证数据保存结果
+ ///
+ private static string VerifyDataSaveResults(UsageStats stats, List saveResults)
+ {
+ var verification = new StringBuilder();
+ verification.AppendLine("数据保存验证结果:");
+ verification.AppendLine(string.Join("\n", saveResults));
+
+ // 验证关键数据是否保存成功
+ try
+ {
+ var savedStats = LoadUsageStats();
+ if (savedStats != null && savedStats.DeviceId == stats.DeviceId)
+ {
+ verification.AppendLine("✓ 主数据文件验证成功");
+ }
+ else
+ {
+ verification.AppendLine("✗ 主数据文件验证失败");
+ }
+ }
+ catch (Exception ex)
+ {
+ verification.AppendLine($"✗ 主数据文件验证异常: {ex.Message}");
+ }
+
+ return verification.ToString();
+ }
+
+ // 内存缓存变量
+ private static UsageStats _cachedUsageStats;
}
}
+
From 710a9014dd618840da790d40b2e5425a8cdf9b3a Mon Sep 17 00:00:00 2001
From: CJKmkp <2564608840@qq.com>
Date: Sat, 23 Aug 2025 21:39:00 +0800
Subject: [PATCH 28/45] improve:issue #112
---
Ink Canvas/Helpers/GlobalHotkeyManager.cs | 301 +++++++++++++++
Ink Canvas/Helpers/InkFadeManager.cs | 264 +++++++++++++
Ink Canvas/Helpers/PPTUIManager.cs | 1 -
Ink Canvas/MainWindow.xaml.cs | 59 ++-
.../MainWindow_cs/MW_ClipboardHandler.cs | 2 +-
.../MainWindow_cs/MW_FloatingBarIcons.cs | 19 +-
Ink Canvas/MainWindow_cs/MW_Hotkeys.cs | 2 +-
Ink Canvas/MainWindow_cs/MW_Screenshot.cs | 2 +-
Ink Canvas/MainWindow_cs/MW_ShapeDrawing.cs | 4 +-
Ink Canvas/Windows/HotkeyItem.xaml | 65 ++++
Ink Canvas/Windows/HotkeyItem.xaml.cs | 166 ++++++++
Ink Canvas/Windows/HotkeySettingsWindow.xaml | 191 ++++++++++
.../Windows/HotkeySettingsWindow.xaml.cs | 357 ++++++++++++++++++
13 files changed, 1414 insertions(+), 19 deletions(-)
create mode 100644 Ink Canvas/Helpers/GlobalHotkeyManager.cs
create mode 100644 Ink Canvas/Helpers/InkFadeManager.cs
create mode 100644 Ink Canvas/Windows/HotkeyItem.xaml
create mode 100644 Ink Canvas/Windows/HotkeyItem.xaml.cs
create mode 100644 Ink Canvas/Windows/HotkeySettingsWindow.xaml
create mode 100644 Ink Canvas/Windows/HotkeySettingsWindow.xaml.cs
diff --git a/Ink Canvas/Helpers/GlobalHotkeyManager.cs b/Ink Canvas/Helpers/GlobalHotkeyManager.cs
new file mode 100644
index 00000000..4ab1a459
--- /dev/null
+++ b/Ink Canvas/Helpers/GlobalHotkeyManager.cs
@@ -0,0 +1,301 @@
+using System;
+using System.Collections.Generic;
+using System.Windows.Input;
+using NHotkey.Wpf;
+
+namespace Ink_Canvas.Helpers
+{
+ ///
+ /// 全局快捷键管理器 - 使用NHotkey库实现全局快捷键功能
+ ///
+ public class GlobalHotkeyManager : IDisposable
+ {
+ #region Private Fields
+ private readonly Dictionary _registeredHotkeys;
+ private readonly MainWindow _mainWindow;
+ private bool _isDisposed = false;
+ #endregion
+
+ #region Constructor
+ public GlobalHotkeyManager(MainWindow mainWindow)
+ {
+ _mainWindow = mainWindow ?? throw new ArgumentNullException(nameof(mainWindow));
+ _registeredHotkeys = new Dictionary();
+ }
+ #endregion
+
+ #region Public Methods
+ ///
+ /// 注册全局快捷键
+ ///
+ /// 快捷键名称
+ /// 按键
+ /// 修饰键
+ /// 执行动作
+ /// 是否注册成功
+ public bool RegisterHotkey(string hotkeyName, Key key, ModifierKeys modifiers, Action action)
+ {
+ try
+ {
+ if (_isDisposed)
+ return false;
+
+ // 如果快捷键已存在,先注销
+ if (_registeredHotkeys.ContainsKey(hotkeyName))
+ {
+ UnregisterHotkey(hotkeyName);
+ }
+
+ // 创建快捷键信息
+ var hotkeyInfo = new HotkeyInfo
+ {
+ Name = hotkeyName,
+ Key = key,
+ Modifiers = modifiers,
+ Action = action
+ };
+
+ // 注册快捷键
+ HotkeyManager.Current.AddOrReplace(hotkeyName, key, modifiers, (sender, e) =>
+ {
+ try
+ {
+ // 确保在主线程中执行
+ _mainWindow.Dispatcher.Invoke(() =>
+ {
+ action?.Invoke();
+ });
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"执行快捷键 {hotkeyName} 时出错: {ex.Message}", LogHelper.LogType.Error);
+ }
+ });
+
+ _registeredHotkeys[hotkeyName] = hotkeyInfo;
+ LogHelper.WriteLogToFile($"成功注册全局快捷键: {hotkeyName} ({modifiers}+{key})", LogHelper.LogType.Event);
+ return true;
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"注册全局快捷键 {hotkeyName} 失败: {ex.Message}", LogHelper.LogType.Error);
+ return false;
+ }
+ }
+
+ ///
+ /// 注销指定快捷键
+ ///
+ /// 快捷键名称
+ /// 是否注销成功
+ public bool UnregisterHotkey(string hotkeyName)
+ {
+ try
+ {
+ if (_isDisposed || !_registeredHotkeys.ContainsKey(hotkeyName))
+ return false;
+
+ HotkeyManager.Current.Remove(hotkeyName);
+ _registeredHotkeys.Remove(hotkeyName);
+ LogHelper.WriteLogToFile($"成功注销全局快捷键: {hotkeyName}", LogHelper.LogType.Event);
+ return true;
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"注销全局快捷键 {hotkeyName} 失败: {ex.Message}", LogHelper.LogType.Error);
+ return false;
+ }
+ }
+
+ ///
+ /// 注销所有快捷键
+ ///
+ public void UnregisterAllHotkeys()
+ {
+ try
+ {
+ if (_isDisposed)
+ return;
+
+ foreach (var hotkeyName in _registeredHotkeys.Keys)
+ {
+ try
+ {
+ HotkeyManager.Current.Remove(hotkeyName);
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"注销快捷键 {hotkeyName} 时出错: {ex.Message}", LogHelper.LogType.Warning);
+ }
+ }
+
+ _registeredHotkeys.Clear();
+ LogHelper.WriteLogToFile("已注销所有全局快捷键", LogHelper.LogType.Event);
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"注销所有快捷键时出错: {ex.Message}", LogHelper.LogType.Error);
+ }
+ }
+
+ ///
+ /// 检查快捷键是否已注册
+ ///
+ /// 快捷键名称
+ /// 是否已注册
+ public bool IsHotkeyRegistered(string hotkeyName)
+ {
+ return _registeredHotkeys.ContainsKey(hotkeyName);
+ }
+
+ ///
+ /// 获取已注册的快捷键列表
+ ///
+ /// 快捷键信息列表
+ public List GetRegisteredHotkeys()
+ {
+ return new List(_registeredHotkeys.Values);
+ }
+
+ ///
+ /// 注册默认快捷键集合
+ ///
+ public void RegisterDefaultHotkeys()
+ {
+ try
+ {
+ // 基本操作快捷键
+ RegisterHotkey("Undo", Key.Z, ModifierKeys.Control, () => _mainWindow.SymbolIconUndo_MouseUp(null, null));
+ RegisterHotkey("Redo", Key.Y, ModifierKeys.Control, () => _mainWindow.SymbolIconRedo_MouseUp(null, null));
+ RegisterHotkey("Clear", Key.E, ModifierKeys.Control, () => _mainWindow.SymbolIconDelete_MouseUp(null, null));
+ RegisterHotkey("Paste", Key.V, ModifierKeys.Control, () => _mainWindow.HandleGlobalPaste(null, null));
+
+ // 工具切换快捷键
+ RegisterHotkey("SelectTool", Key.S, ModifierKeys.Alt, () => _mainWindow.SymbolIconSelect_MouseUp(null, null));
+ RegisterHotkey("DrawTool", Key.D, ModifierKeys.Alt, () => _mainWindow.PenIcon_Click(null, null));
+ RegisterHotkey("EraserTool", Key.E, ModifierKeys.Alt, () => _mainWindow.EraserIcon_Click(null, null));
+ RegisterHotkey("BlackboardTool", Key.B, ModifierKeys.Alt, () => _mainWindow.ImageBlackboard_MouseUp(null, null));
+ RegisterHotkey("QuitDrawTool", Key.Q, ModifierKeys.Alt, () => _mainWindow.CursorIcon_Click(null, null));
+
+ // 画笔快捷键 - 使用反射访问penType字段
+ RegisterHotkey("Pen1", Key.D1, ModifierKeys.Alt, () => SwitchToPenType(0));
+ RegisterHotkey("Pen2", Key.D2, ModifierKeys.Alt, () => SwitchToPenType(1));
+ RegisterHotkey("Pen3", Key.D3, ModifierKeys.Alt, () => SwitchToPenType(2));
+ RegisterHotkey("Pen4", Key.D4, ModifierKeys.Alt, () => SwitchToPenType(3));
+ RegisterHotkey("Pen5", Key.D5, ModifierKeys.Alt, () => SwitchToPenType(4));
+
+ // 功能快捷键
+ RegisterHotkey("DrawLine", Key.L, ModifierKeys.Alt, () => _mainWindow.BtnDrawLine_Click(null, null));
+ RegisterHotkey("Screenshot", Key.C, ModifierKeys.Alt, () => _mainWindow.SaveScreenShotToDesktop());
+ RegisterHotkey("Hide", Key.V, ModifierKeys.Alt, () => _mainWindow.SymbolIconEmoji_MouseUp(null, null));
+
+ // 退出快捷键
+ RegisterHotkey("Exit", Key.Escape, ModifierKeys.None, () => _mainWindow.KeyExit(null, null));
+
+ LogHelper.WriteLogToFile("已注册默认全局快捷键集合", LogHelper.LogType.Event);
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"注册默认快捷键时出错: {ex.Message}", LogHelper.LogType.Error);
+ }
+ }
+
+ ///
+ /// 从设置加载快捷键配置
+ ///
+ public void LoadHotkeysFromSettings()
+ {
+ try
+ {
+ // 这里可以从配置文件或设置中加载自定义快捷键
+ // 暂时使用默认快捷键
+ RegisterDefaultHotkeys();
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"从设置加载快捷键时出错: {ex.Message}", LogHelper.LogType.Error);
+ }
+ }
+
+ ///
+ /// 保存快捷键配置到设置
+ ///
+ public void SaveHotkeysToSettings()
+ {
+ try
+ {
+ // 这里可以将快捷键配置保存到配置文件或设置中
+ LogHelper.WriteLogToFile("快捷键配置已保存", LogHelper.LogType.Event);
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"保存快捷键配置时出错: {ex.Message}", LogHelper.LogType.Error);
+ }
+ }
+ #endregion
+
+ #region Private Helper Methods
+ ///
+ /// 切换到指定笔类型
+ ///
+ /// 笔类型索引
+ private void SwitchToPenType(int penTypeIndex)
+ {
+ try
+ {
+ // 通过反射访问主窗口的penType字段
+ var penTypeField = _mainWindow.GetType().GetField("penType",
+ System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
+
+ if (penTypeField != null)
+ {
+ penTypeField.SetValue(_mainWindow, penTypeIndex);
+
+ // 调用CheckPenTypeUIState方法更新UI状态
+ var checkPenTypeMethod = _mainWindow.GetType().GetMethod("CheckPenTypeUIState",
+ System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
+
+ if (checkPenTypeMethod != null)
+ {
+ checkPenTypeMethod.Invoke(_mainWindow, null);
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"切换到笔类型{penTypeIndex}时出错: {ex.Message}", LogHelper.LogType.Error);
+ }
+ }
+ #endregion
+
+ #region IDisposable Implementation
+ public void Dispose()
+ {
+ if (!_isDisposed)
+ {
+ UnregisterAllHotkeys();
+ _isDisposed = true;
+ }
+ }
+ #endregion
+
+ #region Nested Classes
+ ///
+ /// 快捷键信息类
+ ///
+ public class HotkeyInfo
+ {
+ public string Name { get; set; }
+ public Key Key { get; set; }
+ public ModifierKeys Modifiers { get; set; }
+ public Action Action { get; set; }
+
+ public override string ToString()
+ {
+ var modifiersText = Modifiers == ModifierKeys.None ? "" : $"{Modifiers}+";
+ return $"{modifiersText}{Key}";
+ }
+ }
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/Ink Canvas/Helpers/InkFadeManager.cs b/Ink Canvas/Helpers/InkFadeManager.cs
new file mode 100644
index 00000000..6ddbc874
--- /dev/null
+++ b/Ink Canvas/Helpers/InkFadeManager.cs
@@ -0,0 +1,264 @@
+using System;
+using System.Collections.Generic;
+using System.Windows;
+using System.Windows.Media.Animation;
+using System.Windows.Threading;
+using System.Windows.Ink;
+
+namespace Ink_Canvas.Helpers
+{
+ ///
+ /// 墨迹渐隐管理器 - 管理墨迹的渐隐动画和状态
+ ///
+ public class InkFadeManager
+ {
+ #region Properties
+ ///
+ /// 是否启用墨迹渐隐功能
+ ///
+ public bool IsEnabled { get; set; } = false;
+
+ ///
+ /// 墨迹渐隐时间(毫秒)
+ ///
+ public int FadeTime { get; set; } = 3000;
+
+ ///
+ /// 渐隐动画持续时间(毫秒)
+ ///
+ public int AnimationDuration { get; set; } = 1000;
+ #endregion
+
+ #region Private Fields
+ private readonly MainWindow _mainWindow;
+ private readonly Dispatcher _dispatcher;
+ private readonly Dictionary _fadeTimers;
+ private readonly Dictionary _strokeVisuals;
+ #endregion
+
+ #region Constructor
+ public InkFadeManager(MainWindow mainWindow)
+ {
+ _mainWindow = mainWindow ?? throw new ArgumentNullException(nameof(mainWindow));
+ _dispatcher = _mainWindow.Dispatcher;
+ _fadeTimers = new Dictionary();
+ _strokeVisuals = new Dictionary();
+ }
+ #endregion
+
+ #region Public Methods
+ ///
+ /// 添加需要渐隐的墨迹
+ ///
+ /// 墨迹对象
+ /// 墨迹的视觉元素
+ public void AddFadingStroke(Stroke stroke, UIElement visual)
+ {
+ if (!IsEnabled || stroke == null || visual == null) return;
+
+ try
+ {
+ // 记录墨迹和视觉元素的对应关系
+ _strokeVisuals[stroke] = visual;
+
+ // 创建定时器,在指定时间后开始渐隐动画
+ var timer = new DispatcherTimer
+ {
+ Interval = TimeSpan.FromMilliseconds(FadeTime)
+ };
+
+ timer.Tick += (sender, e) =>
+ {
+ StartFadeAnimation(stroke);
+ timer.Stop();
+ _fadeTimers.Remove(stroke);
+ };
+
+ _fadeTimers[stroke] = timer;
+ timer.Start();
+
+ // 将视觉元素添加到画布上
+ _dispatcher.InvokeAsync(() =>
+ {
+ try
+ {
+ if (_mainWindow.inkCanvas != null)
+ {
+ _mainWindow.inkCanvas.Children.Add(visual);
+ }
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"添加墨迹视觉元素到画布失败: {ex}", LogHelper.LogType.Error);
+ }
+ });
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"添加渐隐墨迹失败: {ex}", LogHelper.LogType.Error);
+ }
+ }
+
+ ///
+ /// 移除墨迹
+ ///
+ /// 要移除的墨迹
+ public void RemoveStroke(Stroke stroke)
+ {
+ if (stroke == null) return;
+
+ try
+ {
+ if (_fadeTimers.TryGetValue(stroke, out var timer))
+ {
+ timer.Stop();
+ _fadeTimers.Remove(stroke);
+ }
+
+ if (_strokeVisuals.TryGetValue(stroke, out var visual))
+ {
+ _dispatcher.InvokeAsync(() =>
+ {
+ try
+ {
+ if (_mainWindow.inkCanvas != null && _mainWindow.inkCanvas.Children.Contains(visual))
+ {
+ _mainWindow.inkCanvas.Children.Remove(visual);
+ }
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"从画布移除墨迹视觉元素失败: {ex}", LogHelper.LogType.Error);
+ }
+ });
+
+ _strokeVisuals.Remove(stroke);
+ }
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"移除渐隐墨迹失败: {ex}", LogHelper.LogType.Error);
+ }
+ }
+
+ ///
+ /// 清除所有渐隐墨迹
+ ///
+ public void ClearAllFadingStrokes()
+ {
+ try
+ {
+ foreach (var timer in _fadeTimers.Values)
+ {
+ timer.Stop();
+ }
+
+ _fadeTimers.Clear();
+
+ _dispatcher.InvokeAsync(() =>
+ {
+ try
+ {
+ if (_mainWindow.inkCanvas != null)
+ {
+ foreach (var visual in _strokeVisuals.Values)
+ {
+ if (_mainWindow.inkCanvas.Children.Contains(visual))
+ {
+ _mainWindow.inkCanvas.Children.Remove(visual);
+ }
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"清除所有墨迹视觉元素失败: {ex}", LogHelper.LogType.Error);
+ }
+ });
+
+ _strokeVisuals.Clear();
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"清除所有渐隐墨迹失败: {ex}", LogHelper.LogType.Error);
+ }
+ }
+
+ ///
+ /// 更新渐隐时间设置
+ ///
+ /// 新的渐隐时间(毫秒)
+ public void UpdateFadeTime(int fadeTime)
+ {
+ FadeTime = fadeTime;
+
+ foreach (var kvp in _fadeTimers)
+ {
+ var stroke = kvp.Key;
+ var timer = kvp.Value;
+
+ timer.Stop();
+ timer.Interval = TimeSpan.FromMilliseconds(FadeTime);
+ timer.Start();
+ }
+ }
+
+ ///
+ /// 更新动画持续时间设置
+ ///
+ /// 新的动画持续时间(毫秒)
+ public void UpdateAnimationDuration(int animationDuration)
+ {
+ AnimationDuration = animationDuration;
+ }
+ #endregion
+
+ #region Private Methods
+ ///
+ /// 开始渐隐动画
+ ///
+ /// 要渐隐的墨迹
+ private void StartFadeAnimation(Stroke stroke)
+ {
+ if (!_strokeVisuals.TryGetValue(stroke, out var visual)) return;
+
+ try
+ {
+ _dispatcher.InvokeAsync(() =>
+ {
+ var fadeAnimation = new DoubleAnimation
+ {
+ From = 1.0,
+ To = 0.0,
+ Duration = TimeSpan.FromMilliseconds(AnimationDuration),
+ EasingFunction = new CubicEase { EasingMode = EasingMode.EaseInOut }
+ };
+
+ fadeAnimation.Completed += (sender, e) =>
+ {
+ try
+ {
+ if (_mainWindow.inkCanvas != null && _mainWindow.inkCanvas.Children.Contains(visual))
+ {
+ _mainWindow.inkCanvas.Children.Remove(visual);
+ }
+
+ RemoveStroke(stroke);
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"渐隐动画完成后清理墨迹失败: {ex}", LogHelper.LogType.Error);
+ }
+ };
+
+ visual.BeginAnimation(UIElement.OpacityProperty, fadeAnimation);
+ });
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"开始渐隐动画失败: {ex}", LogHelper.LogType.Error);
+ }
+ }
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/Ink Canvas/Helpers/PPTUIManager.cs b/Ink Canvas/Helpers/PPTUIManager.cs
index 6fe95e2c..5bf4b636 100644
--- a/Ink Canvas/Helpers/PPTUIManager.cs
+++ b/Ink Canvas/Helpers/PPTUIManager.cs
@@ -3,7 +3,6 @@ using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Threading;
-using Ink_Canvas.Helpers;
namespace Ink_Canvas.Helpers
{
diff --git a/Ink Canvas/MainWindow.xaml.cs b/Ink Canvas/MainWindow.xaml.cs
index 31bc55a5..14a0ff8d 100644
--- a/Ink Canvas/MainWindow.xaml.cs
+++ b/Ink Canvas/MainWindow.xaml.cs
@@ -41,6 +41,9 @@ namespace Ink_Canvas
private int currentPageIndex;
private System.Windows.Controls.Canvas currentCanvas;
private AutoUpdateHelper.UpdateLineGroup AvailableLatestLineGroup;
+
+ // 全局快捷键管理器
+ private GlobalHotkeyManager _globalHotkeyManager;
@@ -495,6 +498,9 @@ namespace Ink_Canvas
// 初始化剪贴板监控
InitializeClipboardMonitoring();
+
+ // 初始化全局快捷键管理器
+ InitializeGlobalHotkeyManager();
}
private void SystemEventsOnDisplaySettingsChanged(object sender, EventArgs e)
@@ -623,6 +629,13 @@ namespace Ink_Canvas
// 清理剪贴板监控
CleanupClipboardMonitoring();
ClipboardNotification.Stop();
+
+ // 清理全局快捷键管理器
+ if (_globalHotkeyManager != null)
+ {
+ _globalHotkeyManager.Dispose();
+ _globalHotkeyManager = null;
+ }
// 停止置顶维护定时器
StopTopmostMaintenance();
@@ -1067,10 +1080,7 @@ namespace Ink_Canvas
// 新增:快捷键设置
private void NavShortcuts_Click(object sender, RoutedEventArgs e)
{
- // 切换到快捷键设置页面
- ShowSettingsSection("shortcuts");
- // 如果设置部分尚未快捷键
- MessageBox.Show("设置功能正在开发中", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
+ OpenHotkeySettingsWindow();
}
private void BtnCloseSettings_Click(object sender, RoutedEventArgs e)
@@ -1955,5 +1965,46 @@ namespace Ink_Canvas
}
#endregion
+
+ #region 全局快捷键管理
+ ///
+ /// 初始化全局快捷键管理器
+ ///
+ private void InitializeGlobalHotkeyManager()
+ {
+ try
+ {
+ _globalHotkeyManager = new GlobalHotkeyManager(this);
+ _globalHotkeyManager.LoadHotkeysFromSettings();
+ LogHelper.WriteLogToFile("全局快捷键管理器已初始化", LogHelper.LogType.Event);
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"初始化全局快捷键管理器时出错: {ex.Message}", LogHelper.LogType.Error);
+ }
+ }
+
+ ///
+ /// 打开快捷键设置窗口
+ ///
+ private void OpenHotkeySettingsWindow()
+ {
+ try
+ {
+ if (_globalHotkeyManager == null)
+ {
+ MessageBox.Show("快捷键管理器尚未初始化,请稍后重试。", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
+ return;
+ }
+ var hotkeySettingsWindow = new HotkeySettingsWindow(this, _globalHotkeyManager);
+ hotkeySettingsWindow.ShowDialog();
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"打开快捷键设置窗口时出错: {ex.Message}", LogHelper.LogType.Error);
+ MessageBox.Show($"打开快捷键设置窗口时出错: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
+ }
+ }
+ #endregion
}
}
diff --git a/Ink Canvas/MainWindow_cs/MW_ClipboardHandler.cs b/Ink Canvas/MainWindow_cs/MW_ClipboardHandler.cs
index de6b9ba3..ee4a6152 100644
--- a/Ink Canvas/MainWindow_cs/MW_ClipboardHandler.cs
+++ b/Ink Canvas/MainWindow_cs/MW_ClipboardHandler.cs
@@ -185,7 +185,7 @@ namespace Ink_Canvas
}
// 处理全局粘贴快捷键
- private async void HandleGlobalPaste(object sender, ExecutedRoutedEventArgs e)
+ internal async void HandleGlobalPaste(object sender, ExecutedRoutedEventArgs e)
{
try
{
diff --git a/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs b/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs
index edd67c3d..67f0ec06 100644
--- a/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs
+++ b/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs
@@ -186,7 +186,7 @@ namespace Ink_Canvas
GridForFloatingBarDraging.Visibility = Visibility.Visible;
}
- private void SymbolIconEmoji_MouseUp(object sender, MouseButtonEventArgs e)
+ internal void SymbolIconEmoji_MouseUp(object sender, MouseButtonEventArgs e)
{
isDragDropInEffect = false;
@@ -495,7 +495,8 @@ namespace Ink_Canvas
#endregion
#region 撤銷重做按鈕
- private void SymbolIconUndo_MouseUp(object sender, MouseButtonEventArgs e)
+
+ internal void SymbolIconUndo_MouseUp(object sender, MouseButtonEventArgs e)
{
//if (lastBorderMouseDownObject != sender) return;
@@ -508,7 +509,7 @@ namespace Ink_Canvas
HideSubPanels();
}
- private void SymbolIconRedo_MouseUp(object sender, MouseButtonEventArgs e)
+ internal void SymbolIconRedo_MouseUp(object sender, MouseButtonEventArgs e)
{
//if (lastBorderMouseDownObject != sender) return;
@@ -528,7 +529,7 @@ namespace Ink_Canvas
//private bool Not_Enter_Blackboard_fir_Mouse_Click = true;
private bool isDisplayingOrHidingBlackboard;
- private void ImageBlackboard_MouseUp(object sender, MouseButtonEventArgs e)
+ internal void ImageBlackboard_MouseUp(object sender, MouseButtonEventArgs e)
{
if (lastBorderMouseDownObject != null && lastBorderMouseDownObject is Panel)
@@ -728,7 +729,7 @@ namespace Ink_Canvas
#region 清空畫布按鈕
- private void SymbolIconDelete_MouseUp(object sender, MouseButtonEventArgs e)
+ internal void SymbolIconDelete_MouseUp(object sender, MouseButtonEventArgs e)
{
if (lastBorderMouseDownObject != null && lastBorderMouseDownObject is Panel)
@@ -778,7 +779,7 @@ namespace Ink_Canvas
///
/// sender
/// MouseButtonEventArgs
- private void SymbolIconSelect_MouseUp(object sender, MouseButtonEventArgs e)
+ internal void SymbolIconSelect_MouseUp(object sender, MouseButtonEventArgs e)
{
if (lastBorderMouseDownObject != null && lastBorderMouseDownObject is Panel)
@@ -1542,7 +1543,7 @@ namespace Ink_Canvas
});
}
- private async void CursorIcon_Click(object sender, RoutedEventArgs e)
+ internal async void CursorIcon_Click(object sender, RoutedEventArgs e)
{
if (lastBorderMouseDownObject != null && lastBorderMouseDownObject is Panel)
((Panel)lastBorderMouseDownObject).Background = new SolidColorBrush(Colors.Transparent);
@@ -1648,7 +1649,7 @@ namespace Ink_Canvas
}
}
- private void PenIcon_Click(object sender, RoutedEventArgs e)
+ internal void PenIcon_Click(object sender, RoutedEventArgs e)
{
if (lastBorderMouseDownObject != null && lastBorderMouseDownObject is Panel)
@@ -1866,7 +1867,7 @@ namespace Ink_Canvas
CheckColorTheme();
}
- private void EraserIcon_Click(object sender, RoutedEventArgs e)
+ internal void EraserIcon_Click(object sender, RoutedEventArgs e)
{
EnterMultiTouchModeIfNeeded();
bool isAlreadyEraser = inkCanvas.EditingMode == InkCanvasEditingMode.EraseByPoint;
diff --git a/Ink Canvas/MainWindow_cs/MW_Hotkeys.cs b/Ink Canvas/MainWindow_cs/MW_Hotkeys.cs
index 594d3a21..79ef9e5f 100644
--- a/Ink Canvas/MainWindow_cs/MW_Hotkeys.cs
+++ b/Ink Canvas/MainWindow_cs/MW_Hotkeys.cs
@@ -57,7 +57,7 @@ namespace Ink_Canvas
}
- private void KeyExit(object sender, ExecutedRoutedEventArgs e)
+ internal void KeyExit(object sender, ExecutedRoutedEventArgs e)
{
if (BtnPPTSlideShowEnd.Visibility == Visibility.Visible) BtnPPTSlideShowEnd_Click(BtnPPTSlideShowEnd, null);
}
diff --git a/Ink Canvas/MainWindow_cs/MW_Screenshot.cs b/Ink Canvas/MainWindow_cs/MW_Screenshot.cs
index 38b40348..00e537fd 100644
--- a/Ink Canvas/MainWindow_cs/MW_Screenshot.cs
+++ b/Ink Canvas/MainWindow_cs/MW_Screenshot.cs
@@ -42,7 +42,7 @@ namespace Ink_Canvas
SaveInkCanvasStrokes(false);
}
- private void SaveScreenShotToDesktop()
+ internal void SaveScreenShotToDesktop()
{
var desktopPath = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory),
diff --git a/Ink Canvas/MainWindow_cs/MW_ShapeDrawing.cs b/Ink Canvas/MainWindow_cs/MW_ShapeDrawing.cs
index 9e520900..fdaf44ba 100644
--- a/Ink Canvas/MainWindow_cs/MW_ShapeDrawing.cs
+++ b/Ink Canvas/MainWindow_cs/MW_ShapeDrawing.cs
@@ -172,8 +172,8 @@ namespace Ink_Canvas
return Task.FromResult(true);
}
-
- private async void BtnDrawLine_Click(object sender, MouseButtonEventArgs e)
+
+ internal async void BtnDrawLine_Click(object sender, MouseButtonEventArgs e)
{
await CheckIsDrawingShapesInMultiTouchMode();
EnterShapeDrawingMode(1);
diff --git a/Ink Canvas/Windows/HotkeyItem.xaml b/Ink Canvas/Windows/HotkeyItem.xaml
new file mode 100644
index 00000000..a7ebf536
--- /dev/null
+++ b/Ink Canvas/Windows/HotkeyItem.xaml
@@ -0,0 +1,65 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Ink Canvas/Windows/HotkeyItem.xaml.cs b/Ink Canvas/Windows/HotkeyItem.xaml.cs
new file mode 100644
index 00000000..3ff70c8c
--- /dev/null
+++ b/Ink Canvas/Windows/HotkeyItem.xaml.cs
@@ -0,0 +1,166 @@
+using System;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Input;
+
+namespace Ink_Canvas.Windows
+{
+ ///
+ /// 快捷键项控件
+ ///
+ public partial class HotkeyItem : UserControl
+ {
+ #region Events
+ ///
+ /// 快捷键变更事件
+ ///
+ public event EventHandler HotkeyChanged;
+ #endregion
+
+ #region Properties
+ public string Title
+ {
+ get => TitleTextBlock.Text;
+ set => TitleTextBlock.Text = value;
+ }
+
+ public string Description
+ {
+ get => DescriptionTextBlock.Text;
+ set => DescriptionTextBlock.Text = value;
+ }
+
+ public string DefaultKey { get; set; }
+ public string DefaultModifiers { get; set; }
+
+ private Key _currentKey = Key.None;
+ private ModifierKeys _currentModifiers = ModifierKeys.None;
+ #endregion
+
+ #region Constructor
+ public HotkeyItem()
+ {
+ InitializeComponent();
+ UpdateHotkeyDisplay();
+ }
+ #endregion
+
+ #region Public Methods
+ ///
+ /// 设置当前快捷键
+ ///
+ /// 按键
+ /// 修饰键
+ public void SetCurrentHotkey(Key key, ModifierKeys modifiers)
+ {
+ _currentKey = key;
+ _currentModifiers = modifiers;
+ UpdateHotkeyDisplay();
+ }
+
+ ///
+ /// 获取当前快捷键
+ ///
+ /// 快捷键信息
+ public (Key key, ModifierKeys modifiers) GetCurrentHotkey()
+ {
+ return (_currentKey, _currentModifiers);
+ }
+ #endregion
+
+ #region Private Methods
+ private void UpdateHotkeyDisplay()
+ {
+ if (_currentKey == Key.None)
+ {
+ CurrentHotkeyTextBlock.Text = "未设置";
+ CurrentHotkeyTextBlock.Foreground = System.Windows.Media.Brushes.Gray;
+ }
+ else
+ {
+ var modifiersText = _currentModifiers == ModifierKeys.None ? "" : $"{_currentModifiers}+";
+ CurrentHotkeyTextBlock.Text = $"{modifiersText}{_currentKey}";
+ CurrentHotkeyTextBlock.Foreground = System.Windows.Media.Brushes.Black;
+ }
+ }
+
+ private void StartHotkeyCapture()
+ {
+ BtnSetHotkey.Content = "请按键...";
+ BtnSetHotkey.Background = System.Windows.Media.Brushes.Orange;
+
+ // 设置焦点以捕获键盘事件
+ Focus();
+
+ // 添加键盘事件处理器
+ KeyDown += HotkeyItem_KeyDown;
+ KeyUp += HotkeyItem_KeyUp;
+ }
+
+ private void StopHotkeyCapture()
+ {
+ BtnSetHotkey.Content = "设置";
+ BtnSetHotkey.Background = System.Windows.Media.Brushes.DodgerBlue;
+
+ // 移除键盘事件处理器
+ KeyDown -= HotkeyItem_KeyDown;
+ KeyUp -= HotkeyItem_KeyUp;
+ }
+
+ private void HotkeyItem_KeyDown(object sender, KeyEventArgs e)
+ {
+ e.Handled = true;
+
+ // 忽略某些特殊键
+ if (e.Key == Key.LeftShift || e.Key == Key.RightShift ||
+ e.Key == Key.LeftCtrl || e.Key == Key.RightCtrl ||
+ e.Key == Key.LeftAlt || e.Key == Key.RightAlt ||
+ e.Key == Key.LWin || e.Key == Key.RWin)
+ {
+ return;
+ }
+
+ // 获取修饰键
+ var modifiers = ModifierKeys.None;
+ if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl))
+ modifiers |= ModifierKeys.Control;
+ if (Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift))
+ modifiers |= ModifierKeys.Shift;
+ if (Keyboard.IsKeyDown(Key.LeftAlt) || Keyboard.IsKeyDown(Key.RightAlt))
+ modifiers |= ModifierKeys.Alt;
+ if (Keyboard.IsKeyDown(Key.LWin) || Keyboard.IsKeyDown(Key.RWin))
+ modifiers |= ModifierKeys.Windows;
+
+ // 设置新的快捷键
+ var oldKey = _currentKey;
+ var oldModifiers = _currentModifiers;
+
+ _currentKey = e.Key;
+ _currentModifiers = modifiers;
+
+ UpdateHotkeyDisplay();
+ StopHotkeyCapture();
+
+ // 触发快捷键变更事件
+ HotkeyChanged?.Invoke(this, new HotkeyChangedEventArgs
+ {
+ HotkeyName = Title,
+ Key = _currentKey,
+ Modifiers = _currentModifiers
+ });
+ }
+
+ private void HotkeyItem_KeyUp(object sender, KeyEventArgs e)
+ {
+ e.Handled = true;
+ }
+ #endregion
+
+ #region Event Handlers
+ private void BtnSetHotkey_Click(object sender, RoutedEventArgs e)
+ {
+ StartHotkeyCapture();
+ }
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/Ink Canvas/Windows/HotkeySettingsWindow.xaml b/Ink Canvas/Windows/HotkeySettingsWindow.xaml
new file mode 100644
index 00000000..68bde7dc
--- /dev/null
+++ b/Ink Canvas/Windows/HotkeySettingsWindow.xaml
@@ -0,0 +1,191 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Ink Canvas/Windows/HotkeySettingsWindow.xaml.cs b/Ink Canvas/Windows/HotkeySettingsWindow.xaml.cs
new file mode 100644
index 00000000..453122cb
--- /dev/null
+++ b/Ink Canvas/Windows/HotkeySettingsWindow.xaml.cs
@@ -0,0 +1,357 @@
+using System;
+using System.Collections.Generic;
+using System.Windows;
+using System.Windows.Input;
+using Ink_Canvas.Helpers;
+
+namespace Ink_Canvas.Windows
+{
+ ///
+ /// 快捷键设置窗口
+ ///
+ public partial class HotkeySettingsWindow : Window
+ {
+ #region Private Fields
+ private readonly MainWindow _mainWindow;
+ private readonly GlobalHotkeyManager _hotkeyManager;
+ private readonly Dictionary _hotkeyItems;
+ #endregion
+
+ #region Constructor
+ public HotkeySettingsWindow(MainWindow mainWindow, GlobalHotkeyManager hotkeyManager)
+ {
+ InitializeComponent();
+ _mainWindow = mainWindow;
+ _hotkeyManager = hotkeyManager;
+ _hotkeyItems = new Dictionary();
+
+ // 隐藏主窗口的设置页面
+ HideMainWindowSettings();
+ InitializeHotkeyItems();
+ LoadCurrentHotkeys();
+ SetupEventHandlers();
+
+ // 注册窗口关闭事件
+ this.Closed += HotkeySettingsWindow_Closed;
+ }
+ #endregion
+
+ #region Private Methods
+ private void InitializeHotkeyItems()
+ {
+ // 初始化快捷键项
+ _hotkeyItems["Undo"] = UndoHotkey;
+ _hotkeyItems["Redo"] = RedoHotkey;
+ _hotkeyItems["Clear"] = ClearHotkey;
+ _hotkeyItems["Paste"] = PasteHotkey;
+ _hotkeyItems["SelectTool"] = SelectToolHotkey;
+ _hotkeyItems["DrawTool"] = DrawToolHotkey;
+ _hotkeyItems["EraserTool"] = EraserToolHotkey;
+ _hotkeyItems["BlackboardTool"] = BlackboardToolHotkey;
+ _hotkeyItems["QuitDrawTool"] = QuitDrawToolHotkey;
+ _hotkeyItems["Pen1"] = Pen1Hotkey;
+ _hotkeyItems["Pen2"] = Pen2Hotkey;
+ _hotkeyItems["Pen3"] = Pen3Hotkey;
+ _hotkeyItems["Pen4"] = Pen4Hotkey;
+ _hotkeyItems["Pen5"] = Pen5Hotkey;
+ _hotkeyItems["DrawLine"] = DrawLineHotkey;
+ _hotkeyItems["Screenshot"] = ScreenshotHotkey;
+ _hotkeyItems["Hide"] = HideHotkey;
+ _hotkeyItems["Exit"] = ExitHotkey;
+ }
+
+ private void LoadCurrentHotkeys()
+ {
+ try
+ {
+ var registeredHotkeys = _hotkeyManager.GetRegisteredHotkeys();
+ foreach (var hotkey in registeredHotkeys)
+ {
+ if (_hotkeyItems.TryGetValue(hotkey.Name, out var hotkeyItem))
+ {
+ hotkeyItem.SetCurrentHotkey(hotkey.Key, hotkey.Modifiers);
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"加载当前快捷键时出错: {ex.Message}", LogHelper.LogType.Error);
+ }
+ }
+
+ private void SetupEventHandlers()
+ {
+ // 为每个快捷键项设置事件处理器
+ foreach (var hotkeyItem in _hotkeyItems.Values)
+ {
+ hotkeyItem.HotkeyChanged += OnHotkeyChanged;
+ }
+ }
+
+ private void OnHotkeyChanged(object sender, HotkeyChangedEventArgs e)
+ {
+ try
+ {
+ // 检查快捷键冲突
+ if (IsHotkeyConflict(e.Key, e.Modifiers, e.HotkeyName))
+ {
+ MessageBox.Show($"快捷键 {e.Modifiers}+{e.Key} 已被其他功能使用,请选择其他组合。",
+ "快捷键冲突", MessageBoxButton.OK, MessageBoxImage.Warning);
+ return;
+ }
+
+ // 更新快捷键管理器
+ UpdateHotkeyInManager(e.HotkeyName, e.Key, e.Modifiers);
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"处理快捷键变更时出错: {ex.Message}", LogHelper.LogType.Error);
+ }
+ }
+
+ private bool IsHotkeyConflict(Key key, ModifierKeys modifiers, string excludeHotkeyName)
+ {
+ var registeredHotkeys = _hotkeyManager.GetRegisteredHotkeys();
+ foreach (var hotkey in registeredHotkeys)
+ {
+ if (hotkey.Name != excludeHotkeyName &&
+ hotkey.Key == key &&
+ hotkey.Modifiers == modifiers)
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private void UpdateHotkeyInManager(string hotkeyName, Key key, ModifierKeys modifiers)
+ {
+ try
+ {
+ // 根据快捷键名称获取对应的动作
+ var action = GetActionForHotkey(hotkeyName);
+ if (action != null)
+ {
+ _hotkeyManager.RegisterHotkey(hotkeyName, key, modifiers, action);
+ }
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"更新快捷键管理器时出错: {ex.Message}", LogHelper.LogType.Error);
+ }
+ }
+
+ private Action GetActionForHotkey(string hotkeyName)
+ {
+ switch (hotkeyName)
+ {
+ case "Undo":
+ return () => _mainWindow.SymbolIconUndo_MouseUp(null, null);
+ case "Redo":
+ return () => _mainWindow.SymbolIconRedo_MouseUp(null, null);
+ case "Clear":
+ return () => _mainWindow.SymbolIconDelete_MouseUp(null, null);
+ case "Paste":
+ return () => _mainWindow.HandleGlobalPaste(null, null);
+ case "SelectTool":
+ return () => _mainWindow.SymbolIconSelect_MouseUp(null, null);
+ case "DrawTool":
+ return () => _mainWindow.PenIcon_Click(null, null);
+ case "EraserTool":
+ return () => _mainWindow.EraserIcon_Click(null, null);
+ case "BlackboardTool":
+ return () => _mainWindow.ImageBlackboard_MouseUp(null, null);
+ case "QuitDrawTool":
+ return () => _mainWindow.CursorIcon_Click(null, null);
+ case "Pen1":
+ return () => SwitchToPenType(0);
+ case "Pen2":
+ return () => SwitchToPenType(1);
+ case "Pen3":
+ return () => SwitchToPenType(2);
+ case "Pen4":
+ return () => SwitchToPenType(3);
+ case "Pen5":
+ return () => SwitchToPenType(4);
+ case "DrawLine":
+ return () => _mainWindow.BtnDrawLine_Click(null, null);
+ case "Screenshot":
+ return () => _mainWindow.SaveScreenShotToDesktop();
+ case "Hide":
+ return () => _mainWindow.SymbolIconEmoji_MouseUp(null, null);
+ case "Exit":
+ return () => _mainWindow.KeyExit(null, null);
+ default:
+ return null;
+ }
+ }
+
+ ///
+ /// 切换到指定笔类型
+ ///
+ /// 笔类型索引
+ private void SwitchToPenType(int penTypeIndex)
+ {
+ try
+ {
+ // 通过反射访问主窗口的penType字段
+ var penTypeField = _mainWindow.GetType().GetField("penType",
+ System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
+
+ if (penTypeField != null)
+ {
+ penTypeField.SetValue(_mainWindow, penTypeIndex);
+
+ // 调用CheckPenTypeUIState方法更新UI状态
+ var checkPenTypeMethod = _mainWindow.GetType().GetMethod("CheckPenTypeUIState",
+ System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
+
+ if (checkPenTypeMethod != null)
+ {
+ checkPenTypeMethod.Invoke(_mainWindow, null);
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"切换到笔类型{penTypeIndex}时出错: {ex.Message}", LogHelper.LogType.Error);
+ }
+ }
+ #endregion
+
+ #region MainWindow Settings Management
+ ///
+ /// 隐藏主窗口的设置页面
+ ///
+ private void HideMainWindowSettings()
+ {
+ try
+ {
+ // 通过反射访问主窗口的设置面板
+ var settingsBorder = _mainWindow.GetType().GetField("BorderSettings",
+ System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)?.GetValue(_mainWindow) as System.Windows.Controls.Border;
+
+ if (settingsBorder != null)
+ {
+ settingsBorder.Visibility = System.Windows.Visibility.Collapsed;
+ }
+
+ // 隐藏设置蒙版
+ var settingsMask = _mainWindow.GetType().GetField("BorderSettingsMask",
+ System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)?.GetValue(_mainWindow) as System.Windows.Controls.Border;
+
+ if (settingsMask != null)
+ {
+ settingsMask.Visibility = System.Windows.Visibility.Collapsed;
+ }
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"隐藏主窗口设置页面时出错: {ex.Message}", LogHelper.LogType.Error);
+ }
+ }
+
+ ///
+ /// 显示主窗口的设置页面
+ ///
+ private void ShowMainWindowSettings()
+ {
+ try
+ {
+ // 通过反射访问主窗口的设置面板
+ var settingsBorder = _mainWindow.GetType().GetField("BorderSettings",
+ System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)?.GetValue(_mainWindow) as System.Windows.Controls.Border;
+
+ if (settingsBorder != null)
+ {
+ settingsBorder.Visibility = System.Windows.Visibility.Visible;
+ }
+
+ // 显示设置蒙版
+ var settingsMask = _mainWindow.GetType().GetField("BorderSettingsMask",
+ System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)?.GetValue(_mainWindow) as System.Windows.Controls.Border;
+
+ if (settingsMask != null)
+ {
+ settingsMask.Visibility = System.Windows.Visibility.Visible;
+ }
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"显示主窗口设置页面时出错: {ex.Message}", LogHelper.LogType.Error);
+ }
+ }
+ #endregion
+
+ #region Window Event Handlers
+ ///
+ /// 窗口关闭事件处理
+ ///
+ private void HotkeySettingsWindow_Closed(object sender, EventArgs e)
+ {
+ // 恢复主窗口设置页面的显示
+ ShowMainWindowSettings();
+ }
+ #endregion
+
+ #region Event Handlers
+ private void BtnClose_Click(object sender, RoutedEventArgs e)
+ {
+ Close();
+ }
+
+ private void BtnResetToDefault_Click(object sender, RoutedEventArgs e)
+ {
+ try
+ {
+ var result = MessageBox.Show("确定要重置所有快捷键为默认设置吗?",
+ "确认重置", MessageBoxButton.YesNo, MessageBoxImage.Question);
+ if (result == MessageBoxResult.Yes)
+ {
+ // 重置为默认快捷键
+ _hotkeyManager.RegisterDefaultHotkeys();
+
+ // 更新UI显示
+ LoadCurrentHotkeys();
+
+ MessageBox.Show("快捷键已重置为默认设置。", "重置完成", MessageBoxButton.OK, MessageBoxImage.Information);
+ }
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"重置快捷键时出错: {ex.Message}", LogHelper.LogType.Error);
+ MessageBox.Show($"重置快捷键时出错: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
+ }
+ }
+
+ private void BtnSave_Click(object sender, RoutedEventArgs e)
+ {
+ try
+ {
+ // 保存快捷键配置
+ _hotkeyManager.SaveHotkeysToSettings();
+
+ MessageBox.Show("快捷键设置已保存。", "保存成功", MessageBoxButton.OK, MessageBoxImage.Information);
+ Close();
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"保存快捷键设置时出错: {ex.Message}", LogHelper.LogType.Error);
+ MessageBox.Show($"保存快捷键设置时出错: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
+ }
+ }
+ #endregion
+ }
+
+ #region Hotkey Changed Event Args
+ ///
+ /// 快捷键变更事件参数
+ ///
+ public class HotkeyChangedEventArgs : EventArgs
+ {
+ public string HotkeyName { get; set; }
+ public Key Key { get; set; }
+ public ModifierKeys Modifiers { get; set; }
+ }
+ #endregion
+}
\ No newline at end of file
From 5665fcc8230a0f715c698045149f133ba1ae568b Mon Sep 17 00:00:00 2001
From: CJKmkp <2564608840@qq.com>
Date: Sat, 23 Aug 2025 23:13:39 +0800
Subject: [PATCH 29/45] add:issue #131
---
Ink Canvas/Helpers/InkFadeManager.cs | 683 +++++++++++++++++-
Ink Canvas/MainWindow.xaml | 88 ++-
Ink Canvas/MainWindow.xaml.cs | 110 +++
Ink Canvas/MainWindow_cs/MW_Settings.cs | 108 ++-
Ink Canvas/MainWindow_cs/MW_SettingsToLoad.cs | 63 +-
.../MW_SimulatePressure&InkToShape.cs | 30 +
Ink Canvas/MainWindow_cs/MW_TouchEvents.cs | 23 +-
Ink Canvas/Resources/Settings.cs | 7 +
8 files changed, 1019 insertions(+), 93 deletions(-)
diff --git a/Ink Canvas/Helpers/InkFadeManager.cs b/Ink Canvas/Helpers/InkFadeManager.cs
index 6ddbc874..df935494 100644
--- a/Ink Canvas/Helpers/InkFadeManager.cs
+++ b/Ink Canvas/Helpers/InkFadeManager.cs
@@ -1,9 +1,14 @@
using System;
using System.Collections.Generic;
+using System.Linq;
using System.Windows;
using System.Windows.Media.Animation;
using System.Windows.Threading;
using System.Windows.Ink;
+using System.Windows.Controls;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Shapes;
namespace Ink_Canvas.Helpers
{
@@ -34,6 +39,8 @@ namespace Ink_Canvas.Helpers
private readonly Dispatcher _dispatcher;
private readonly Dictionary _fadeTimers;
private readonly Dictionary _strokeVisuals;
+ private readonly Dictionary _strokeStartPoints;
+ private readonly Dictionary _strokeEndPoints;
#endregion
#region Constructor
@@ -43,6 +50,8 @@ namespace Ink_Canvas.Helpers
_dispatcher = _mainWindow.Dispatcher;
_fadeTimers = new Dictionary();
_strokeVisuals = new Dictionary();
+ _strokeStartPoints = new Dictionary();
+ _strokeEndPoints = new Dictionary();
}
#endregion
@@ -51,15 +60,31 @@ namespace Ink_Canvas.Helpers
/// 添加需要渐隐的墨迹
///
/// 墨迹对象
- /// 墨迹的视觉元素
- public void AddFadingStroke(Stroke stroke, UIElement visual)
+ /// 落笔点
+ /// 抬笔点
+ public void AddFadingStroke(Stroke stroke, Point startPoint, Point endPoint)
{
- if (!IsEnabled || stroke == null || visual == null) return;
+ LogHelper.WriteLogToFile($"AddFadingStroke 被调用,IsEnabled: {IsEnabled}, stroke: {(stroke != null ? "非空" : "空")}", LogHelper.LogType.Info);
+
+ if (!IsEnabled || stroke == null)
+ {
+ LogHelper.WriteLogToFile($"AddFadingStroke 被拒绝,IsEnabled: {IsEnabled}, stroke: {(stroke != null ? "非空" : "空")}", LogHelper.LogType.Warning);
+ return;
+ }
try
{
- // 记录墨迹和视觉元素的对应关系
- _strokeVisuals[stroke] = visual;
+ LogHelper.WriteLogToFile($"开始添加渐隐墨迹,渐隐时间:{FadeTime}ms,动画时间:{AnimationDuration}ms", LogHelper.LogType.Info);
+
+ // 记录墨迹的起点和终点
+ _strokeStartPoints[stroke] = startPoint;
+ _strokeEndPoints[stroke] = endPoint;
+
+ // 创建墨迹的视觉元素(湿墨迹状态)
+ var strokeVisual = CreateStrokeVisual(stroke);
+ if (strokeVisual == null) return;
+
+ _strokeVisuals[stroke] = strokeVisual;
// 创建定时器,在指定时间后开始渐隐动画
var timer = new DispatcherTimer
@@ -69,6 +94,7 @@ namespace Ink_Canvas.Helpers
timer.Tick += (sender, e) =>
{
+ LogHelper.WriteLogToFile("定时器触发,开始渐隐动画", LogHelper.LogType.Info);
StartFadeAnimation(stroke);
timer.Stop();
_fadeTimers.Remove(stroke);
@@ -77,6 +103,8 @@ namespace Ink_Canvas.Helpers
_fadeTimers[stroke] = timer;
timer.Start();
+ LogHelper.WriteLogToFile($"定时器已启动,将在 {FadeTime}ms 后开始渐隐", LogHelper.LogType.Info);
+
// 将视觉元素添加到画布上
_dispatcher.InvokeAsync(() =>
{
@@ -84,7 +112,20 @@ namespace Ink_Canvas.Helpers
{
if (_mainWindow.inkCanvas != null)
{
- _mainWindow.inkCanvas.Children.Add(visual);
+ // 将墨迹添加到 inkCanvas 的父容器中,而不是 inkCanvas.Children
+ // 这样可以避免坐标系统问题
+ var parent = _mainWindow.inkCanvas.Parent as System.Windows.Controls.Panel;
+ if (parent != null)
+ {
+ parent.Children.Add(strokeVisual);
+ LogHelper.WriteLogToFile("墨迹已添加到父容器", LogHelper.LogType.Info);
+ }
+ else
+ {
+ // 如果无法获取父容器,则添加到 inkCanvas.Children
+ _mainWindow.inkCanvas.Children.Add(strokeVisual);
+ LogHelper.WriteLogToFile("墨迹已添加到 inkCanvas.Children", LogHelper.LogType.Info);
+ }
}
}
catch (Exception ex)
@@ -121,7 +162,13 @@ namespace Ink_Canvas.Helpers
{
try
{
- if (_mainWindow.inkCanvas != null && _mainWindow.inkCanvas.Children.Contains(visual))
+ // 从父容器中移除墨迹
+ var parent = _mainWindow.inkCanvas?.Parent as System.Windows.Controls.Panel;
+ if (parent != null && parent.Children.Contains(visual))
+ {
+ parent.Children.Remove(visual);
+ }
+ else if (_mainWindow.inkCanvas != null && _mainWindow.inkCanvas.Children.Contains(visual))
{
_mainWindow.inkCanvas.Children.Remove(visual);
}
@@ -134,6 +181,9 @@ namespace Ink_Canvas.Helpers
_strokeVisuals.Remove(stroke);
}
+
+ _strokeStartPoints.Remove(stroke);
+ _strokeEndPoints.Remove(stroke);
}
catch (Exception ex)
{
@@ -161,9 +211,14 @@ namespace Ink_Canvas.Helpers
{
if (_mainWindow.inkCanvas != null)
{
+ var parent = _mainWindow.inkCanvas.Parent as System.Windows.Controls.Panel;
foreach (var visual in _strokeVisuals.Values)
{
- if (_mainWindow.inkCanvas.Children.Contains(visual))
+ if (parent != null && parent.Children.Contains(visual))
+ {
+ parent.Children.Remove(visual);
+ }
+ else if (_mainWindow.inkCanvas.Children.Contains(visual))
{
_mainWindow.inkCanvas.Children.Remove(visual);
}
@@ -177,6 +232,8 @@ namespace Ink_Canvas.Helpers
});
_strokeVisuals.Clear();
+ _strokeStartPoints.Clear();
+ _strokeEndPoints.Clear();
}
catch (Exception ex)
{
@@ -203,17 +260,107 @@ namespace Ink_Canvas.Helpers
}
}
+
+
///
- /// 更新动画持续时间设置
+ /// 启用墨迹渐隐功能
///
- /// 新的动画持续时间(毫秒)
- public void UpdateAnimationDuration(int animationDuration)
+ public void Enable()
{
- AnimationDuration = animationDuration;
+ IsEnabled = true;
+ LogHelper.WriteLogToFile("墨迹渐隐功能已启用", LogHelper.LogType.Info);
+ }
+
+ ///
+ /// 禁用墨迹渐隐功能
+ ///
+ public void Disable()
+ {
+ IsEnabled = false;
+ LogHelper.WriteLogToFile("墨迹渐隐功能已禁用", LogHelper.LogType.Info);
}
#endregion
#region Private Methods
+ ///
+ /// 创建墨迹的视觉元素
+ ///
+ /// 墨迹对象
+ /// 视觉元素
+ private UIElement CreateStrokeVisual(Stroke stroke)
+ {
+ try
+ {
+ LogHelper.WriteLogToFile("开始创建墨迹视觉元素", LogHelper.LogType.Info);
+
+ // 创建路径几何,使用墨迹的实际位置
+ var geometry = stroke.GetGeometry();
+ if (geometry == null)
+ {
+ LogHelper.WriteLogToFile("墨迹几何为空,无法创建视觉元素", LogHelper.LogType.Error);
+ return null;
+ }
+
+ LogHelper.WriteLogToFile($"墨迹几何边界:{geometry.Bounds}", LogHelper.LogType.Info);
+
+ // 获取绘画属性
+ var drawingAttribs = stroke.DrawingAttributes;
+
+ // 创建路径元素,确保使用正确的绘画属性
+ var path = new Path
+ {
+ Data = geometry,
+ Stroke = new SolidColorBrush(drawingAttribs.Color),
+ StrokeThickness = drawingAttribs.Width, // 使用原始墨迹的粗细
+ StrokeStartLineCap = PenLineCap.Round,
+ StrokeEndLineCap = PenLineCap.Round,
+ StrokeLineJoin = PenLineJoin.Round,
+ Fill = drawingAttribs.IsHighlighter ? new SolidColorBrush(drawingAttribs.Color) : null, // 高亮笔需要填充
+ Opacity = 0.95, // 初始透明度更高,显得更自然
+
+ // 优化渲染质量
+ UseLayoutRounding = false,
+ SnapsToDevicePixels = false
+ };
+
+ // 如果是高亮笔,调整透明度和混合模式
+ if (drawingAttribs.IsHighlighter)
+ {
+ path.Opacity = 0.4; // 高亮笔初始透明度更低,更符合荧光笔特性
+
+ // 为高亮笔添加特殊的混合效果
+ // 使用更柔和的笔触样式
+ path.StrokeStartLineCap = PenLineCap.Flat;
+ path.StrokeEndLineCap = PenLineCap.Flat;
+ path.StrokeLineJoin = PenLineJoin.Miter;
+
+ // 高亮笔通常需要更宽的笔触来覆盖下面的内容
+ if (drawingAttribs.Width < 20)
+ {
+ path.StrokeThickness = Math.Max(drawingAttribs.Width * 1.5, 20);
+ }
+
+ LogHelper.WriteLogToFile($"高亮笔特殊处理:透明度={path.Opacity},笔触宽度={path.StrokeThickness}", LogHelper.LogType.Info);
+ }
+
+ // 不设置任何变换,保持墨迹原有粗细
+ var bounds = geometry.Bounds;
+
+ // 设置墨迹的初始位置
+ System.Windows.Controls.Canvas.SetLeft(path, bounds.Left);
+ System.Windows.Controls.Canvas.SetTop(path, bounds.Top);
+
+ LogHelper.WriteLogToFile($"墨迹视觉元素创建完成,位置:({bounds.Left}, {bounds.Top}),大小:{bounds.Width} x {bounds.Height},粗细:{drawingAttribs.Width},高亮笔:{drawingAttribs.IsHighlighter}", LogHelper.LogType.Info);
+
+ return path;
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"创建墨迹视觉元素失败: {ex}", LogHelper.LogType.Error);
+ return null;
+ }
+ }
+
///
/// 开始渐隐动画
///
@@ -224,34 +371,23 @@ namespace Ink_Canvas.Helpers
try
{
+ LogHelper.WriteLogToFile("开始执行渐隐动画", LogHelper.LogType.Info);
+
_dispatcher.InvokeAsync(() =>
{
- var fadeAnimation = new DoubleAnimation
+ // 获取当前透明度和判断是否为高亮笔
+ var currentOpacity = visual.Opacity;
+ var isHighlighter = stroke.DrawingAttributes.IsHighlighter;
+
+ // 根据墨迹类型选择不同的动画效果
+ if (isHighlighter)
{
- From = 1.0,
- To = 0.0,
- Duration = TimeSpan.FromMilliseconds(AnimationDuration),
- EasingFunction = new CubicEase { EasingMode = EasingMode.EaseInOut }
- };
-
- fadeAnimation.Completed += (sender, e) =>
+ StartHighlighterFadeAnimation(visual, stroke, currentOpacity);
+ }
+ else
{
- try
- {
- if (_mainWindow.inkCanvas != null && _mainWindow.inkCanvas.Children.Contains(visual))
- {
- _mainWindow.inkCanvas.Children.Remove(visual);
- }
-
- RemoveStroke(stroke);
- }
- catch (Exception ex)
- {
- LogHelper.WriteLogToFile($"渐隐动画完成后清理墨迹失败: {ex}", LogHelper.LogType.Error);
- }
- };
-
- visual.BeginAnimation(UIElement.OpacityProperty, fadeAnimation);
+ StartNormalStrokeFadeAnimation(visual, stroke, currentOpacity);
+ }
});
}
catch (Exception ex)
@@ -259,6 +395,481 @@ namespace Ink_Canvas.Helpers
LogHelper.WriteLogToFile($"开始渐隐动画失败: {ex}", LogHelper.LogType.Error);
}
}
+
+ ///
+ /// 开始普通墨迹的渐隐动画
+ ///
+ private void StartNormalStrokeFadeAnimation(UIElement visual, Stroke stroke, double currentOpacity)
+ {
+ try
+ {
+ LogHelper.WriteLogToFile("开始普通墨迹渐进式渐隐动画", LogHelper.LogType.Info);
+ StartProgressiveFadeAnimation(visual, stroke, currentOpacity, AnimationDuration);
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"开始普通墨迹渐隐动画失败: {ex}", LogHelper.LogType.Error);
+ }
+ }
+
+ ///
+ /// 开始高亮笔的渐隐动画
+ ///
+ private void StartHighlighterFadeAnimation(UIElement visual, Stroke stroke, double currentOpacity)
+ {
+ try
+ {
+ LogHelper.WriteLogToFile("开始高亮笔渐进式渐隐动画", LogHelper.LogType.Info);
+ StartProgressiveFadeAnimation(visual, stroke, currentOpacity, (int)(AnimationDuration * 1.5));
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"开始高亮笔渐隐动画失败: {ex}", LogHelper.LogType.Error);
+ }
+ }
+
+ ///
+ /// 渐进式渐隐动画 - 从起点到终点逐渐消失
+ ///
+ private void StartProgressiveFadeAnimation(UIElement visual, Stroke stroke, double currentOpacity, int duration)
+ {
+ try
+ {
+ LogHelper.WriteLogToFile($"开始渐进式渐隐动画,墨迹点数:{stroke.StylusPoints.Count}", LogHelper.LogType.Info);
+
+ // 确保所有墨迹都能显示动画,包括短墨迹
+ if (stroke.StylusPoints.Count < 2)
+ {
+ // 只有1个点的墨迹也使用分段动画,确保视觉效果
+ CreateSegmentedStroke(visual, stroke, currentOpacity, duration);
+ return;
+ }
+
+ // 将墨迹分段并创建多个 Path
+ CreateSegmentedStroke(visual, stroke, currentOpacity, duration);
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"渐进式渐隐动画失败: {ex}", LogHelper.LogType.Error);
+ // 失败时回退到简单动画
+ StartSimpleFadeAnimation(visual, stroke, currentOpacity, duration);
+ }
+ }
+
+ ///
+ /// 创建分段墨迹并开始渐进消失
+ ///
+ private void CreateSegmentedStroke(UIElement originalVisual, Stroke stroke, double opacity, int duration)
+ {
+ try
+ {
+ var stylusPoints = stroke.StylusPoints;
+ var totalPoints = stylusPoints.Count;
+
+ // 分段算法 - 确保所有墨迹都有足够的动画效果
+ var strokeLength = CalculateStrokeLength(stylusPoints);
+ var segmentCount = CalculateOptimalSegmentCount(totalPoints, strokeLength);
+
+ // 强制最小分段数量,确保短墨迹也有动画效果
+ segmentCount = Math.Max(segmentCount, 4);
+
+ var pointsPerSegment = Math.Max(1, totalPoints / segmentCount);
+
+ LogHelper.WriteLogToFile($"创建 {segmentCount} 个分段,每段约 {pointsPerSegment} 个点", LogHelper.LogType.Info);
+
+ // 隐藏原始视觉元素
+ originalVisual.Visibility = Visibility.Hidden;
+
+ var segments = new List();
+ var parent = _mainWindow.inkCanvas?.Parent as System.Windows.Controls.Panel;
+ if (parent == null)
+ {
+ // 如果父容器不是Panel,直接使用InkCanvas
+ parent = null; // 稍后会检查并使用InkCanvas.Children
+ }
+
+ // 创建各个分段 - 确保短墨迹也能正确分段
+ for (int i = 0; i < segmentCount; i++)
+ {
+ var startIndex = i * pointsPerSegment;
+ var endIndex = (i == segmentCount - 1) ? totalPoints - 1 : (i + 1) * pointsPerSegment;
+
+ // 确保有足够的点来创建分段,对于短墨迹特殊处理
+ if (endIndex <= startIndex && totalPoints > 1)
+ {
+ // 短墨迹:每个点作为一个分段
+ startIndex = i;
+ endIndex = Math.Min(i + 1, totalPoints - 1);
+ }
+
+ // 为每个分段添加重叠,确保连接处平滑
+ var overlap = Math.Max(1, pointsPerSegment / 6); // 15%的重叠,平衡平滑与速度
+ var actualStartIndex = Math.Max(0, startIndex - overlap);
+ var actualEndIndex = Math.Min(totalPoints - 1, endIndex + overlap);
+
+ var segment = CreateStrokeSegment(stroke, actualStartIndex, actualEndIndex, opacity);
+ if (segment != null)
+ {
+ segments.Add(segment);
+ if (parent != null)
+ {
+ parent.Children.Add(segment);
+ }
+ else if (_mainWindow.inkCanvas != null)
+ {
+ _mainWindow.inkCanvas.Children.Add(segment);
+ }
+ }
+ }
+
+ // 开始分段渐隐动画
+ StartSegmentedFadeAnimation(segments, stroke, originalVisual, duration);
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"创建分段墨迹失败: {ex}", LogHelper.LogType.Error);
+ StartSimpleFadeAnimation(originalVisual, stroke, opacity, duration);
+ }
+ }
+
+ ///
+ /// 创建墨迹分段
+ ///
+ private UIElement CreateStrokeSegment(Stroke originalStroke, int startIndex, int endIndex, double opacity)
+ {
+ try
+ {
+ // 创建分段的 StylusPoint 集合
+ var segmentPoints = new StylusPointCollection();
+ for (int i = startIndex; i <= endIndex && i < originalStroke.StylusPoints.Count; i++)
+ {
+ segmentPoints.Add(originalStroke.StylusPoints[i]);
+ }
+
+ if (segmentPoints.Count < 2) return null;
+
+ // 创建分段墨迹
+ var segmentStroke = new Stroke(segmentPoints)
+ {
+ DrawingAttributes = originalStroke.DrawingAttributes.Clone()
+ };
+
+ // 创建分段的视觉元素
+ var geometry = segmentStroke.GetGeometry();
+ if (geometry == null) return null;
+
+ var drawingAttribs = segmentStroke.DrawingAttributes;
+ var path = new Path
+ {
+ Data = geometry,
+ Stroke = new SolidColorBrush(drawingAttribs.Color),
+ StrokeThickness = drawingAttribs.Width,
+ StrokeStartLineCap = drawingAttribs.IsHighlighter ? PenLineCap.Flat : PenLineCap.Round,
+ StrokeEndLineCap = drawingAttribs.IsHighlighter ? PenLineCap.Flat : PenLineCap.Round,
+ StrokeLineJoin = drawingAttribs.IsHighlighter ? PenLineJoin.Miter : PenLineJoin.Round,
+ Fill = drawingAttribs.IsHighlighter ? new SolidColorBrush(drawingAttribs.Color) : null,
+ Opacity = opacity,
+ UseLayoutRounding = false,
+ SnapsToDevicePixels = false
+ };
+
+ // 设置位置
+ var bounds = geometry.Bounds;
+ System.Windows.Controls.Canvas.SetLeft(path, bounds.Left);
+ System.Windows.Controls.Canvas.SetTop(path, bounds.Top);
+
+ return path;
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"创建墨迹分段失败: {ex}", LogHelper.LogType.Error);
+ return null;
+ }
+ }
+
+ ///
+ /// 开始分段渐隐动画
+ ///
+ private void StartSegmentedFadeAnimation(List segments, Stroke originalStroke, UIElement originalVisual, int totalDuration)
+ {
+ try
+ {
+ LogHelper.WriteLogToFile($"开始 {segments.Count} 个分段的渐隐动画", LogHelper.LogType.Info);
+
+ // 动画时序算法
+ var segmentDuration = CalculateOptimalSegmentDuration(totalDuration, segments.Count);
+ var animationCurve = CreateAppleStyleAnimationCurve(segments.Count, totalDuration);
+
+ // 跟踪动画完成状态
+ var completedSegments = new HashSet();
+ var totalSegments = segments.Count;
+
+ // 渐隐效果 - 使用自然的动画曲线
+ for (int i = 0; i < segments.Count; i++)
+ {
+ var segment = segments[i];
+
+ // 使用预计算的动画曲线获取延迟时间
+ var delay = animationCurve[i];
+
+ // 使用定时器延迟启动每个分段的动画
+ var timer = new DispatcherTimer
+ {
+ Interval = TimeSpan.FromMilliseconds(delay)
+ };
+
+ int segmentIndex = i; // 捕获当前索引
+ timer.Tick += (sender, e) =>
+ {
+ StartSingleSegmentFadeAnimation(segment, segmentDuration, () =>
+ {
+ // 动画完成回调
+ lock (completedSegments)
+ {
+ completedSegments.Add(segment);
+ LogHelper.WriteLogToFile($"分段 {segmentIndex} 动画完成,已完成 {completedSegments.Count}/{totalSegments}", LogHelper.LogType.Info);
+
+ // 检查是否所有分段都完成了
+ if (completedSegments.Count >= totalSegments)
+ {
+ LogHelper.WriteLogToFile("所有分段动画完成,开始清理", LogHelper.LogType.Info);
+ CleanupSegmentedAnimation(segments, originalStroke, originalVisual);
+ }
+ }
+ });
+ timer.Stop();
+ };
+
+ timer.Start();
+ }
+
+ // 设置一个安全超时定时器,防止无限等待
+ var safetyTimeout = totalDuration + (segments.Count * segmentDuration) + 1200; // 额外1.2秒缓冲,确保动画完整
+ var safetyTimer = new DispatcherTimer
+ {
+ Interval = TimeSpan.FromMilliseconds(safetyTimeout)
+ };
+
+ safetyTimer.Tick += (sender, e) =>
+ {
+ LogHelper.WriteLogToFile($"安全超时触发,强制清理动画", LogHelper.LogType.Warning);
+ CleanupSegmentedAnimation(segments, originalStroke, originalVisual);
+ safetyTimer.Stop();
+ };
+
+ safetyTimer.Start();
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"分段渐隐动画失败: {ex}", LogHelper.LogType.Error);
+ CleanupSegmentedAnimation(segments, originalStroke, originalVisual);
+ }
+ }
+
+ ///
+ /// 单个分段的渐隐动画
+ ///
+ private void StartSingleSegmentFadeAnimation(UIElement segment, int duration, Action onCompleted = null)
+ {
+ try
+ {
+ // 只使用透明度动画,保持墨迹原有粗细
+ var fadeAnimation = new DoubleAnimation
+ {
+ From = segment.Opacity,
+ To = 0.0,
+ Duration = TimeSpan.FromMilliseconds(duration),
+ EasingFunction = new CubicEase { EasingMode = EasingMode.EaseInOut } // 更平滑的缓动
+ };
+
+ // 添加动画完成事件
+ if (onCompleted != null)
+ {
+ fadeAnimation.Completed += (sender, e) =>
+ {
+ onCompleted?.Invoke();
+ };
+ }
+
+ // 只应用透明度动画,不改变墨迹大小
+ segment.BeginAnimation(UIElement.OpacityProperty, fadeAnimation);
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"单个分段渐隐动画失败: {ex}", LogHelper.LogType.Error);
+ // 即使失败也要调用完成回调
+ onCompleted?.Invoke();
+ }
+ }
+
+ ///
+ /// 清理分段动画
+ ///
+ private void CleanupSegmentedAnimation(List segments, Stroke originalStroke, UIElement originalVisual)
+ {
+ try
+ {
+ LogHelper.WriteLogToFile("清理分段渐隐动画", LogHelper.LogType.Info);
+
+ // 移除所有分段
+ var parent = _mainWindow.inkCanvas?.Parent as System.Windows.Controls.Panel;
+
+ foreach (var segment in segments)
+ {
+ if (parent != null && parent.Children.Contains(segment))
+ {
+ parent.Children.Remove(segment);
+ }
+ else if (_mainWindow.inkCanvas != null && _mainWindow.inkCanvas.Children.Contains(segment))
+ {
+ _mainWindow.inkCanvas.Children.Remove(segment);
+ }
+ }
+
+ // 清理原始墨迹
+ OnAnimationCompleted(originalVisual, originalStroke);
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"清理分段动画失败: {ex}", LogHelper.LogType.Error);
+ }
+ }
+
+ ///
+ /// 简单渐隐动画(备用方案)
+ ///
+ private void StartSimpleFadeAnimation(UIElement visual, Stroke stroke, double currentOpacity, int duration)
+ {
+ try
+ {
+ LogHelper.WriteLogToFile("使用简单渐隐动画", LogHelper.LogType.Info);
+
+ var fadeAnimation = new DoubleAnimation
+ {
+ From = currentOpacity,
+ To = 0.0,
+ Duration = TimeSpan.FromMilliseconds(duration),
+ EasingFunction = new QuadraticEase { EasingMode = EasingMode.EaseIn }
+ };
+
+ fadeAnimation.Completed += (sender, e) => OnAnimationCompleted(visual, stroke);
+ visual.BeginAnimation(UIElement.OpacityProperty, fadeAnimation);
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"简单渐隐动画失败: {ex}", LogHelper.LogType.Error);
+ OnAnimationCompleted(visual, stroke);
+ }
+ }
+
+ ///
+ /// 计算墨迹的实际长度
+ ///
+ private double CalculateStrokeLength(StylusPointCollection points)
+ {
+ if (points.Count < 2) return 0;
+
+ double totalLength = 0;
+ for (int i = 1; i < points.Count; i++)
+ {
+ var p1 = points[i - 1].ToPoint();
+ var p2 = points[i].ToPoint();
+ totalLength += Math.Sqrt(Math.Pow(p2.X - p1.X, 2) + Math.Pow(p2.Y - p1.Y, 2));
+ }
+ return totalLength;
+ }
+
+ ///
+ /// 根据墨迹特性计算最优分段数量 - 平衡速度与完整性
+ ///
+ private int CalculateOptimalSegmentCount(int pointCount, double strokeLength)
+ {
+ // 平衡速度与完整性,确保动画效果的同时提高速度
+ const double PIXELS_PER_SEGMENT = 12.0; // 每段适中长度,平衡效果与速度
+ const int MIN_SEGMENTS = 5; // 适当的最小分段数,确保动画效果
+ const int MAX_SEGMENTS = 100; // 适中的最大分段数,平衡性能与效果
+
+ // 根据长度计算基础分段数
+ var lengthBasedSegments = Math.Max(MIN_SEGMENTS, (int)(strokeLength / PIXELS_PER_SEGMENT));
+
+ // 根据点密度调整,平衡效果与速度
+ var density = pointCount > 0 ? strokeLength / pointCount : 1;
+ var densityFactor = Math.Max(0.4, Math.Min(2.5, density / 1.8));
+
+ var finalSegments = (int)(lengthBasedSegments * densityFactor);
+
+ // 对于短墨迹,确保至少有4个分段
+ if (pointCount <= 5)
+ {
+ finalSegments = Math.Max(finalSegments, 4);
+ }
+
+ // 限制在合理范围内
+ return Math.Min(MAX_SEGMENTS, Math.Max(MIN_SEGMENTS, finalSegments));
+ }
+
+ ///
+ /// 计算最优的单段动画持续时间 - 平衡速度与完整性
+ ///
+ private int CalculateOptimalSegmentDuration(int totalDuration, int segmentCount)
+ {
+ // 平衡速度与动画完整性
+ var baseDuration = totalDuration / Math.Max(segmentCount, 1);
+ var minDuration = 150; // 每段最少150ms,确保动画完整显示
+ var maxDuration = 500; // 每段最多500ms,平衡速度与完整性
+
+ return Math.Max(minDuration, Math.Min(maxDuration, baseDuration));
+ }
+
+ ///
+ /// 创建优化的动画时间曲线 - 平衡速度与完整性
+ ///
+ private int[] CreateAppleStyleAnimationCurve(int segmentCount, int totalDuration)
+ {
+ var curve = new int[segmentCount];
+
+ // 平衡速度与完整性,确保动画有足够时间播放
+ var availableTime = totalDuration * 0.6; // 使用60%的总时间,给动画留足够缓冲
+ var delayBetweenSegments = Math.Max(60, availableTime / Math.Max(segmentCount, 1));
+
+ for (int i = 0; i < segmentCount; i++)
+ {
+ // 线性延迟,确保每个分段都有足够时间
+ curve[i] = (int)(i * delayBetweenSegments);
+ }
+
+ return curve;
+ }
+
+ ///
+ /// 动画完成后的统一处理
+ ///
+ private void OnAnimationCompleted(UIElement visual, Stroke stroke)
+ {
+ try
+ {
+ LogHelper.WriteLogToFile("渐隐动画完成,开始清理墨迹", LogHelper.LogType.Info);
+
+ // 从父容器中移除墨迹
+ var parent = _mainWindow.inkCanvas?.Parent as System.Windows.Controls.Panel;
+ if (parent != null && parent.Children.Contains(visual))
+ {
+ parent.Children.Remove(visual);
+ LogHelper.WriteLogToFile("墨迹已从父容器移除", LogHelper.LogType.Info);
+ }
+ else if (_mainWindow.inkCanvas != null && _mainWindow.inkCanvas.Children.Contains(visual))
+ {
+ _mainWindow.inkCanvas.Children.Remove(visual);
+ LogHelper.WriteLogToFile("墨迹已从 inkCanvas.Children 移除", LogHelper.LogType.Info);
+ }
+
+ RemoveStroke(stroke);
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"渐隐动画完成后清理墨迹失败: {ex}", LogHelper.LogType.Error);
+ }
+ }
#endregion
}
}
\ No newline at end of file
diff --git a/Ink Canvas/MainWindow.xaml b/Ink Canvas/MainWindow.xaml
index 9597d615..f9f94034 100644
--- a/Ink Canvas/MainWindow.xaml
+++ b/Ink Canvas/MainWindow.xaml
@@ -832,6 +832,27 @@
IsOn="True" FontFamily="Microsoft YaHei UI" FontWeight="Bold"
Toggled="ToggleSwitchAdvancedBezierSmoothing_Toggled" />
+
+
+
+
+
+
+
+
+
+
+
+
@@ -1197,16 +1218,16 @@
-
+
-
+
@@ -1215,16 +1236,16 @@
-
+
-
+
@@ -1233,16 +1254,16 @@
-
+
-
+
@@ -1251,16 +1272,16 @@
-
+
-
+
@@ -1268,9 +1289,9 @@
-
+
@@ -7948,7 +7969,7 @@
+ CornerRadius="5" Margin="-170,-140,-147,37">
+
+
+
+
+
+ /// 初始化墨迹渐隐管理器
+ ///
+ private void InitializeInkFadeManager()
+ {
+ try
+ {
+ // 确保墨迹渐隐管理器已初始化
+ if (_inkFadeManager == null)
+ {
+ _inkFadeManager = new InkFadeManager(this);
+ }
+
+ // 同步设置状态
+ _inkFadeManager.IsEnabled = Settings.Canvas.EnableInkFade;
+ _inkFadeManager.UpdateFadeTime(Settings.Canvas.InkFadeTime);
+
+ LogHelper.WriteLogToFile("墨迹渐隐管理器已初始化", LogHelper.LogType.Event);
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"初始化墨迹渐隐管理器时出错: {ex.Message}", LogHelper.LogType.Error);
+ }
+ }
+
///
/// 初始化全局快捷键管理器
///
@@ -2006,5 +2047,74 @@ namespace Ink_Canvas
}
}
#endregion
+
+ #region 墨迹渐隐功能
+ ///
+ /// 墨迹渐隐开关切换事件处理
+ ///
+ private void ToggleSwitchEnableInkFade_Toggled(object sender, RoutedEventArgs e)
+ {
+ try
+ {
+ Settings.Canvas.EnableInkFade = ToggleSwitchEnableInkFade.IsOn;
+ _inkFadeManager.IsEnabled = Settings.Canvas.EnableInkFade;
+
+ // 同步批注子面板中的开关状态
+ if (ToggleSwitchInkFadeInPanel != null)
+ {
+ ToggleSwitchInkFadeInPanel.IsOn = Settings.Canvas.EnableInkFade;
+ }
+
+ LogHelper.WriteLogToFile($"墨迹渐隐功能已{(Settings.Canvas.EnableInkFade ? "启用" : "禁用")}", LogHelper.LogType.Event);
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"切换墨迹渐隐功能时出错: {ex.Message}", LogHelper.LogType.Error);
+ }
+ }
+
+ ///
+ /// 墨迹渐隐时间滑块值改变事件处理
+ ///
+ private void InkFadeTimeSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs e)
+ {
+ try
+ {
+ Settings.Canvas.InkFadeTime = (int)e.NewValue;
+ _inkFadeManager.UpdateFadeTime(Settings.Canvas.InkFadeTime);
+ LogHelper.WriteLogToFile($"墨迹渐隐时间已更新为 {Settings.Canvas.InkFadeTime}ms", LogHelper.LogType.Event);
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"更新墨迹渐隐时间时出错: {ex.Message}", LogHelper.LogType.Error);
+ }
+ }
+
+
+
+ ///
+ /// 批注子面板中墨迹渐隐开关切换事件处理
+ ///
+ private void ToggleSwitchInkFadeInPanel_Toggled(object sender, RoutedEventArgs e)
+ {
+ try
+ {
+ Settings.Canvas.EnableInkFade = ToggleSwitchInkFadeInPanel.IsOn;
+ _inkFadeManager.IsEnabled = Settings.Canvas.EnableInkFade;
+
+ // 同步设置面板中的开关状态
+ if (ToggleSwitchEnableInkFade != null)
+ {
+ ToggleSwitchEnableInkFade.IsOn = Settings.Canvas.EnableInkFade;
+ }
+
+ LogHelper.WriteLogToFile($"批注子面板中墨迹渐隐功能已{(Settings.Canvas.EnableInkFade ? "启用" : "禁用")}", LogHelper.LogType.Event);
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"批注子面板中切换墨迹渐隐功能时出错: {ex.Message}", LogHelper.LogType.Error);
+ }
+ }
+ #endregion
}
}
diff --git a/Ink Canvas/MainWindow_cs/MW_Settings.cs b/Ink Canvas/MainWindow_cs/MW_Settings.cs
index 011c9842..03054a45 100644
--- a/Ink Canvas/MainWindow_cs/MW_Settings.cs
+++ b/Ink Canvas/MainWindow_cs/MW_Settings.cs
@@ -2405,74 +2405,146 @@ namespace Ink_Canvas
#region 浮动栏按钮显示控制
- private void ToggleSwitchShowShapeButton_Toggled(object sender, RoutedEventArgs e)
+ private void CheckBoxShowShapeButton_Checked(object sender, RoutedEventArgs e)
{
if (!isLoaded) return;
- Settings.Appearance.IsShowShapeButton = ToggleSwitchShowShapeButton.IsOn;
+ Settings.Appearance.IsShowShapeButton = CheckBoxShowShapeButton.IsChecked ?? false;
UpdateFloatingBarButtonsVisibility();
SaveSettingsToFile();
}
- private void ToggleSwitchShowUndoButton_Toggled(object sender, RoutedEventArgs e)
+ private void CheckBoxShowShapeButton_Unchecked(object sender, RoutedEventArgs e)
{
if (!isLoaded) return;
- Settings.Appearance.IsShowUndoButton = ToggleSwitchShowUndoButton.IsOn;
+ Settings.Appearance.IsShowShapeButton = CheckBoxShowShapeButton.IsChecked ?? false;
UpdateFloatingBarButtonsVisibility();
SaveSettingsToFile();
}
- private void ToggleSwitchShowRedoButton_Toggled(object sender, RoutedEventArgs e)
+ private void CheckBoxShowUndoButton_Checked(object sender, RoutedEventArgs e)
{
if (!isLoaded) return;
- Settings.Appearance.IsShowRedoButton = ToggleSwitchShowRedoButton.IsOn;
+ Settings.Appearance.IsShowUndoButton = CheckBoxShowUndoButton.IsChecked ?? false;
UpdateFloatingBarButtonsVisibility();
SaveSettingsToFile();
}
- private void ToggleSwitchShowClearButton_Toggled(object sender, RoutedEventArgs e)
+ private void CheckBoxShowUndoButton_Unchecked(object sender, RoutedEventArgs e)
{
if (!isLoaded) return;
- Settings.Appearance.IsShowClearButton = ToggleSwitchShowClearButton.IsOn;
+ Settings.Appearance.IsShowUndoButton = CheckBoxShowUndoButton.IsChecked ?? false;
UpdateFloatingBarButtonsVisibility();
SaveSettingsToFile();
}
- private void ToggleSwitchShowWhiteboardButton_Toggled(object sender, RoutedEventArgs e)
+ private void CheckBoxShowRedoButton_Checked(object sender, RoutedEventArgs e)
{
if (!isLoaded) return;
- Settings.Appearance.IsShowWhiteboardButton = ToggleSwitchShowWhiteboardButton.IsOn;
+ Settings.Appearance.IsShowRedoButton = CheckBoxShowRedoButton.IsChecked ?? false;
+ UpdateFloatingBarButtonsVisibility();
+ SaveSettingsToFile();
+ }
+
+ private void CheckBoxShowRedoButton_Unchecked(object sender, RoutedEventArgs e)
+ {
+ if (!isLoaded) return;
+ Settings.Appearance.IsShowRedoButton = CheckBoxShowRedoButton.IsChecked ?? false;
+ UpdateFloatingBarButtonsVisibility();
+ SaveSettingsToFile();
+ }
+
+ private void CheckBoxShowClearButton_Checked(object sender, RoutedEventArgs e)
+ {
+ if (!isLoaded) return;
+ Settings.Appearance.IsShowClearButton = CheckBoxShowClearButton.IsChecked ?? false;
+ UpdateFloatingBarButtonsVisibility();
+ SaveSettingsToFile();
+ }
+
+ private void CheckBoxShowClearButton_Unchecked(object sender, RoutedEventArgs e)
+ {
+ if (!isLoaded) return;
+ Settings.Appearance.IsShowClearButton = CheckBoxShowClearButton.IsChecked ?? false;
+ UpdateFloatingBarButtonsVisibility();
+ SaveSettingsToFile();
+ }
+
+ private void CheckBoxShowWhiteboardButton_Checked(object sender, RoutedEventArgs e)
+ {
+ if (!isLoaded) return;
+ Settings.Appearance.IsShowWhiteboardButton = CheckBoxShowWhiteboardButton.IsChecked ?? false;
+ UpdateFloatingBarButtonsVisibility();
+ SaveSettingsToFile();
+ }
+
+ private void CheckBoxShowWhiteboardButton_Unchecked(object sender, RoutedEventArgs e)
+ {
+ if (!isLoaded) return;
+ Settings.Appearance.IsShowWhiteboardButton = CheckBoxShowWhiteboardButton.IsChecked ?? false;
UpdateFloatingBarButtonsVisibility();
SaveSettingsToFile();
}
- private void ToggleSwitchShowLassoSelectButton_Toggled(object sender, RoutedEventArgs e)
+ private void CheckBoxShowLassoSelectButton_Checked(object sender, RoutedEventArgs e)
{
if (!isLoaded) return;
- Settings.Appearance.IsShowLassoSelectButton = ToggleSwitchShowLassoSelectButton.IsOn;
+ Settings.Appearance.IsShowLassoSelectButton = CheckBoxShowLassoSelectButton.IsChecked ?? false;
UpdateFloatingBarButtonsVisibility();
SaveSettingsToFile();
}
- private void ToggleSwitchShowClearAndMouseButton_Toggled(object sender, RoutedEventArgs e)
+ private void CheckBoxShowLassoSelectButton_Unchecked(object sender, RoutedEventArgs e)
{
if (!isLoaded) return;
- Settings.Appearance.IsShowClearAndMouseButton = ToggleSwitchShowClearAndMouseButton.IsOn;
+ Settings.Appearance.IsShowLassoSelectButton = CheckBoxShowLassoSelectButton.IsChecked ?? false;
UpdateFloatingBarButtonsVisibility();
SaveSettingsToFile();
}
- private void ToggleSwitchShowHideButton_Toggled(object sender, RoutedEventArgs e)
+ private void CheckBoxShowClearAndMouseButton_Checked(object sender, RoutedEventArgs e)
{
if (!isLoaded) return;
- Settings.Appearance.IsShowHideButton = ToggleSwitchShowHideButton.IsOn;
+ Settings.Appearance.IsShowClearAndMouseButton = CheckBoxShowClearAndMouseButton.IsChecked ?? false;
UpdateFloatingBarButtonsVisibility();
SaveSettingsToFile();
}
- private void ToggleSwitchShowQuickColorPalette_Toggled(object sender, RoutedEventArgs e)
+ private void CheckBoxShowClearAndMouseButton_Unchecked(object sender, RoutedEventArgs e)
{
if (!isLoaded) return;
- Settings.Appearance.IsShowQuickColorPalette = ToggleSwitchShowQuickColorPalette.IsOn;
+ Settings.Appearance.IsShowClearAndMouseButton = CheckBoxShowClearAndMouseButton.IsChecked ?? false;
+ UpdateFloatingBarButtonsVisibility();
+ SaveSettingsToFile();
+ }
+
+ private void CheckBoxShowHideButton_Checked(object sender, RoutedEventArgs e)
+ {
+ if (!isLoaded) return;
+ Settings.Appearance.IsShowHideButton = CheckBoxShowHideButton.IsChecked ?? false;
+ UpdateFloatingBarButtonsVisibility();
+ SaveSettingsToFile();
+ }
+
+ private void CheckBoxShowHideButton_Unchecked(object sender, RoutedEventArgs e)
+ {
+ if (!isLoaded) return;
+ Settings.Appearance.IsShowHideButton = CheckBoxShowHideButton.IsChecked ?? false;
+ UpdateFloatingBarButtonsVisibility();
+ SaveSettingsToFile();
+ }
+
+ private void CheckBoxShowQuickColorPalette_Checked(object sender, RoutedEventArgs e)
+ {
+ if (!isLoaded) return;
+ Settings.Appearance.IsShowQuickColorPalette = CheckBoxShowQuickColorPalette.IsChecked ?? false;
+ UpdateFloatingBarButtonsVisibility();
+ SaveSettingsToFile();
+ }
+
+ private void CheckBoxShowQuickColorPalette_Unchecked(object sender, RoutedEventArgs e)
+ {
+ if (!isLoaded) return;
+ Settings.Appearance.IsShowQuickColorPalette = CheckBoxShowQuickColorPalette.IsChecked ?? false;
UpdateFloatingBarButtonsVisibility();
SaveSettingsToFile();
}
diff --git a/Ink Canvas/MainWindow_cs/MW_SettingsToLoad.cs b/Ink Canvas/MainWindow_cs/MW_SettingsToLoad.cs
index 454f45a1..dfb93232 100644
--- a/Ink Canvas/MainWindow_cs/MW_SettingsToLoad.cs
+++ b/Ink Canvas/MainWindow_cs/MW_SettingsToLoad.cs
@@ -307,15 +307,15 @@ namespace Ink_Canvas
Settings.Appearance.EnableChickenSoupInWhiteboardMode;
// 浮动栏按钮显示控制开关初始化
- ToggleSwitchShowShapeButton.IsOn = Settings.Appearance.IsShowShapeButton;
- ToggleSwitchShowUndoButton.IsOn = Settings.Appearance.IsShowUndoButton;
- ToggleSwitchShowRedoButton.IsOn = Settings.Appearance.IsShowRedoButton;
- ToggleSwitchShowClearButton.IsOn = Settings.Appearance.IsShowClearButton;
- ToggleSwitchShowWhiteboardButton.IsOn = Settings.Appearance.IsShowWhiteboardButton;
- ToggleSwitchShowHideButton.IsOn = Settings.Appearance.IsShowHideButton;
- ToggleSwitchShowQuickColorPalette.IsOn = Settings.Appearance.IsShowQuickColorPalette;
- ToggleSwitchShowLassoSelectButton.IsOn = Settings.Appearance.IsShowLassoSelectButton;
- ToggleSwitchShowClearAndMouseButton.IsOn = Settings.Appearance.IsShowClearAndMouseButton;
+ CheckBoxShowShapeButton.IsChecked = Settings.Appearance.IsShowShapeButton;
+ CheckBoxShowUndoButton.IsChecked = Settings.Appearance.IsShowUndoButton;
+ CheckBoxShowRedoButton.IsChecked = Settings.Appearance.IsShowRedoButton;
+ CheckBoxShowClearButton.IsChecked = Settings.Appearance.IsShowClearButton;
+ CheckBoxShowWhiteboardButton.IsChecked = Settings.Appearance.IsShowWhiteboardButton;
+ CheckBoxShowHideButton.IsChecked = Settings.Appearance.IsShowHideButton;
+ CheckBoxShowQuickColorPalette.IsChecked = Settings.Appearance.IsShowQuickColorPalette;
+ CheckBoxShowLassoSelectButton.IsChecked = Settings.Appearance.IsShowLassoSelectButton;
+ CheckBoxShowClearAndMouseButton.IsChecked = Settings.Appearance.IsShowClearAndMouseButton;
ComboBoxEraserDisplayOption.SelectedIndex = Settings.Appearance.EraserDisplayOption;
ComboBoxQuickColorPaletteDisplayMode.SelectedIndex = Settings.Appearance.QuickColorPaletteDisplayMode;
@@ -883,6 +883,51 @@ namespace Ink_Canvas
{
ViewboxFloatingBarMarginAnimation(100, true);
}
+
+ // 加载墨迹渐隐设置
+ LoadInkFadeSettings();
+ }
+
+ ///
+ /// 加载墨迹渐隐设置
+ ///
+ private void LoadInkFadeSettings()
+ {
+ try
+ {
+ // 同步设置面板中的开关状态
+ if (ToggleSwitchEnableInkFade != null)
+ {
+ ToggleSwitchEnableInkFade.IsOn = Settings.Canvas.EnableInkFade;
+ }
+
+ // 同步批注子面板中的开关状态
+ if (ToggleSwitchInkFadeInPanel != null)
+ {
+ ToggleSwitchInkFadeInPanel.IsOn = Settings.Canvas.EnableInkFade;
+ }
+
+ // 同步滑块值
+ if (InkFadeTimeSlider != null)
+ {
+ InkFadeTimeSlider.Value = Settings.Canvas.InkFadeTime;
+ }
+
+
+
+ // 同步墨迹渐隐管理器的状态
+ if (_inkFadeManager != null)
+ {
+ _inkFadeManager.IsEnabled = Settings.Canvas.EnableInkFade;
+ _inkFadeManager.UpdateFadeTime(Settings.Canvas.InkFadeTime);
+ }
+
+ LogHelper.WriteLogToFile("墨迹渐隐设置已加载", LogHelper.LogType.Event);
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"加载墨迹渐隐设置时出错: {ex.Message}", LogHelper.LogType.Error);
+ }
}
}
}
\ No newline at end of file
diff --git a/Ink Canvas/MainWindow_cs/MW_SimulatePressure&InkToShape.cs b/Ink Canvas/MainWindow_cs/MW_SimulatePressure&InkToShape.cs
index 4dae95ad..4a6c108f 100644
--- a/Ink Canvas/MainWindow_cs/MW_SimulatePressure&InkToShape.cs
+++ b/Ink Canvas/MainWindow_cs/MW_SimulatePressure&InkToShape.cs
@@ -56,6 +56,36 @@ namespace Ink_Canvas
private void inkCanvas_StrokeCollected(object sender, InkCanvasStrokeCollectedEventArgs e)
{
+ // 检查是否启用墨迹渐隐功能
+ if (Settings.Canvas.EnableInkFade)
+ {
+ LogHelper.WriteLogToFile("StrokeCollected: 进入墨迹渐隐模式", LogHelper.LogType.Info);
+
+ // 获取墨迹的起点和终点
+ var startPoint = e.Stroke.StylusPoints.Count > 0 ? e.Stroke.StylusPoints[0].ToPoint() : new Point();
+ var endPoint = e.Stroke.StylusPoints.Count > 0 ? e.Stroke.StylusPoints[e.Stroke.StylusPoints.Count - 1].ToPoint() : new Point();
+
+ // 从InkCanvas中移除墨迹,因为我们要用渐隐管理器来管理它
+ if (inkCanvas.Strokes.Contains(e.Stroke))
+ {
+ inkCanvas.Strokes.Remove(e.Stroke);
+ }
+
+ // 添加到墨迹渐隐管理器
+ if (_inkFadeManager != null)
+ {
+ _inkFadeManager.AddFadingStroke(e.Stroke, startPoint, endPoint);
+ LogHelper.WriteLogToFile($"StrokeCollected: 墨迹已添加到渐隐管理器,起点:{startPoint},终点:{endPoint}", LogHelper.LogType.Info);
+ }
+ else
+ {
+ LogHelper.WriteLogToFile("StrokeCollected: 墨迹渐隐管理器为空,无法添加墨迹", LogHelper.LogType.Error);
+ }
+
+ // 墨迹渐隐模式下不参与墨迹纠正和其他处理,直接返回
+ return;
+ }
+
// 标记是否进行了直线拉直
bool wasStraightened = false;
diff --git a/Ink Canvas/MainWindow_cs/MW_TouchEvents.cs b/Ink Canvas/MainWindow_cs/MW_TouchEvents.cs
index 44a9671d..0c3bbf74 100644
--- a/Ink Canvas/MainWindow_cs/MW_TouchEvents.cs
+++ b/Ink Canvas/MainWindow_cs/MW_TouchEvents.cs
@@ -139,10 +139,13 @@ namespace Ink_Canvas
private void MainWindow_StylusDown(object sender, StylusDownEventArgs e)
{
+ LogHelper.WriteLogToFile($"MainWindow_StylusDown 被调用,笔尾状态: {e.StylusDevice.Inverted}, 当前 drawingShapeMode: {drawingShapeMode}, 当前 EditingMode: {inkCanvas.EditingMode}", LogHelper.LogType.Info);
+
// 新增:根据是否为笔尾自动切换橡皮擦/画笔模式
if (e.StylusDevice.Inverted)
{
inkCanvas.EditingMode = InkCanvasEditingMode.EraseByPoint;
+ LogHelper.WriteLogToFile("检测到笔尾,设置 EditingMode 为 EraseByPoint", LogHelper.LogType.Info);
}
else
{
@@ -151,12 +154,18 @@ namespace Ink_Canvas
{
// 确保几何绘制模式下不切换到Ink模式,避免触摸轨迹被收集
inkCanvas.EditingMode = InkCanvasEditingMode.None;
+ LogHelper.WriteLogToFile("几何绘制模式,设置 EditingMode 为 None", LogHelper.LogType.Info);
return;
}
// 修复:保持当前的线擦模式,不要强制切换到Ink模式
if (inkCanvas.EditingMode != InkCanvasEditingMode.EraseByStroke)
{
inkCanvas.EditingMode = InkCanvasEditingMode.Ink;
+ LogHelper.WriteLogToFile("设置 EditingMode 为 Ink", LogHelper.LogType.Info);
+ }
+ else
+ {
+ LogHelper.WriteLogToFile("保持当前线擦模式", LogHelper.LogType.Info);
}
}
SetCursorBasedOnEditingMode(inkCanvas);
@@ -198,15 +207,25 @@ namespace Ink_Canvas
{
try
{
- inkCanvas.Strokes.Add(GetStrokeVisual(e.StylusDevice.Id).Stroke);
+ LogHelper.WriteLogToFile($"MainWindow_StylusUp 被调用,EditingMode: {inkCanvas.EditingMode}, EnableInkFade: {Settings.Canvas.EnableInkFade}", LogHelper.LogType.Info);
+
+ var stroke = GetStrokeVisual(e.StylusDevice.Id).Stroke;
+ LogHelper.WriteLogToFile($"获取到墨迹,StylusPoints数量: {stroke.StylusPoints.Count}", LogHelper.LogType.Info);
+
+ // 正常模式:添加到画布并参与墨迹纠正
+ // 墨迹渐隐功能现在在 StrokeCollected 事件中统一处理所有输入方式
+ LogHelper.WriteLogToFile("StylusUp: 添加墨迹到画布", LogHelper.LogType.Info);
+
+ inkCanvas.Strokes.Add(stroke);
await Task.Delay(5); // 避免渲染墨迹完成前预览墨迹被删除导致墨迹闪烁
inkCanvas.Children.Remove(GetVisualCanvas(e.StylusDevice.Id));
inkCanvas_StrokeCollected(inkCanvas,
- new InkCanvasStrokeCollectedEventArgs(GetStrokeVisual(e.StylusDevice.Id).Stroke));
+ new InkCanvasStrokeCollectedEventArgs(stroke));
}
catch (Exception ex)
{
+ LogHelper.WriteLogToFile($"MainWindow_StylusUp 出错: {ex}", LogHelper.LogType.Error);
Label.Content = ex.ToString();
}
diff --git a/Ink Canvas/Resources/Settings.cs b/Ink Canvas/Resources/Settings.cs
index a80971c5..b617f46d 100644
--- a/Ink Canvas/Resources/Settings.cs
+++ b/Ink Canvas/Resources/Settings.cs
@@ -92,6 +92,13 @@ namespace Ink_Canvas
public bool ClearCanvasAlsoClearImages { get; set; } = true;
[JsonProperty("showCircleCenter")]
public bool ShowCircleCenter { get; set; } = false;
+
+ // 墨迹渐隐功能设置
+ [JsonProperty("enableInkFade")]
+ public bool EnableInkFade { get; set; } = false; // 是否启用墨迹渐隐功能
+ [JsonProperty("inkFadeTime")]
+ public int InkFadeTime { get; set; } = 3000; // 墨迹渐隐时间(毫秒)
+
}
public enum OptionalOperation
From bd4e1c1810244da03b55dbdd2e8163495e6a512d Mon Sep 17 00:00:00 2001
From: CJKmkp <2564608840@qq.com>
Date: Sat, 23 Aug 2025 23:32:44 +0800
Subject: [PATCH 30/45] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E7=89=88=E6=9C=AC?=
=?UTF-8?q?=E5=8F=B7?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Ink Canvas/AssemblyInfo.cs | 4 ++--
Ink Canvas/Properties/AssemblyInfo.cs | 4 ++--
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/Ink Canvas/AssemblyInfo.cs b/Ink Canvas/AssemblyInfo.cs
index 858d6840..d97781ce 100644
--- a/Ink Canvas/AssemblyInfo.cs
+++ b/Ink Canvas/AssemblyInfo.cs
@@ -49,5 +49,5 @@ using System.Windows;
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("1.7.7.5")]
-[assembly: AssemblyFileVersion("1.7.7.5")]
+[assembly: AssemblyVersion("1.7.7.6")]
+[assembly: AssemblyFileVersion("1.7.7.6")]
diff --git a/Ink Canvas/Properties/AssemblyInfo.cs b/Ink Canvas/Properties/AssemblyInfo.cs
index c95995da..5c0248e6 100644
--- a/Ink Canvas/Properties/AssemblyInfo.cs
+++ b/Ink Canvas/Properties/AssemblyInfo.cs
@@ -49,5 +49,5 @@ using System.Windows;
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("1.7.7.5")]
-[assembly: AssemblyFileVersion("1.7.7.5")]
+[assembly: AssemblyVersion("1.7.7.6")]
+[assembly: AssemblyFileVersion("1.7.7.6")]
From 83529cfe095675b1b3950e7f9e3abf4e195d02dd Mon Sep 17 00:00:00 2001
From: CJKmkp <2564608840@qq.com>
Date: Sun, 24 Aug 2025 00:05:26 +0800
Subject: [PATCH 31/45] add:issue #135 #136
---
.../MainWindow_cs/MW_FloatingBarIcons.cs | 2 +-
Ink Canvas/Windows/RandWindow.xaml | 24 ++++++++++++------
Ink Canvas/Windows/RandWindow.xaml.cs | 25 ++++++++++++++++---
3 files changed, 38 insertions(+), 13 deletions(-)
diff --git a/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs b/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs
index 67f0ec06..d16e083f 100644
--- a/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs
+++ b/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs
@@ -997,7 +997,7 @@ namespace Ink_Canvas
{
Process.Start(new ProcessStartInfo
{
- FileName = "classisland://plugins/IslandCaller/Run",
+ FileName = "classisland://plugins/IslandCaller/Simple/1",
UseShellExecute = true
});
}
diff --git a/Ink Canvas/Windows/RandWindow.xaml b/Ink Canvas/Windows/RandWindow.xaml
index 00ef6d31..f1bada9c 100644
--- a/Ink Canvas/Windows/RandWindow.xaml
+++ b/Ink Canvas/Windows/RandWindow.xaml
@@ -103,14 +103,22 @@
-
-
-
-
-
-
-
-
+
+
+ ClassIsland点名
+ SecRandom点名
+ NamePicker点名
+
+
+
+
+
+
+
+
+
+
diff --git a/Ink Canvas/Windows/RandWindow.xaml.cs b/Ink Canvas/Windows/RandWindow.xaml.cs
index 13cfd923..3e801682 100644
--- a/Ink Canvas/Windows/RandWindow.xaml.cs
+++ b/Ink Canvas/Windows/RandWindow.xaml.cs
@@ -295,13 +295,13 @@ namespace Ink_Canvas
// 将 isIslandCallerFirstClick 设为静态字段,实现全局记录
private static bool isIslandCallerFirstClick = true;
- private void BorderBtnIslandCaller_MouseUp(object sender, MouseButtonEventArgs e)
+ private void BorderBtnExternalCaller_MouseUp(object sender, MouseButtonEventArgs e)
{
if (isIslandCallerFirstClick)
{
MessageBox.Show(
- "首次使用ClassIsland点名功能,请确保已安装ClassIsland和Island caller插件。\n" +
- "如未安装,请前往官网下载并安装后再使用。如果安装请再次点击此按钮。",
+ "首次使用外部点名功能,请确保已安装相应的点名软件。\n" +
+ "如未安装,请前往官网下载并安装后再使用。如果已安装请再次点击此按钮。",
"提示", MessageBoxButton.OK, MessageBoxImage.Information);
isIslandCallerFirstClick = false;
return;
@@ -309,9 +309,26 @@ namespace Ink_Canvas
try
{
+ string protocol = "";
+ switch (ComboBoxCallerType.SelectedIndex)
+ {
+ case 0: // ClassIsland点名
+ protocol = "classisland://plugins/IslandCaller/Simple/1";
+ break;
+ case 1: // SecRandom点名
+ protocol = "secrandom://pumping?action=start";
+ break;
+ case 2: // NamePicker点名
+ protocol = "namepicker://调起没有浮窗的NamePicker";
+ break;
+ default:
+ protocol = "classisland://plugins/IslandCaller/Simple/1";
+ break;
+ }
+
Process.Start(new ProcessStartInfo
{
- FileName = "classisland://plugins/IslandCaller/Run",
+ FileName = protocol,
UseShellExecute = true
});
}
From 14eedca93981a72a16443d561700fd9e2d2f19bc Mon Sep 17 00:00:00 2001
From: CJKmkp <2564608840@qq.com>
Date: Sun, 24 Aug 2025 01:46:48 +0800
Subject: [PATCH 32/45] =?UTF-8?q?fix:=E6=97=B6=E9=97=B4=E6=88=B3=E9=97=AE?=
=?UTF-8?q?=E9=A2=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Ink Canvas/App.xaml.cs | 29 +++++++++++++++++++++++++++--
1 file changed, 27 insertions(+), 2 deletions(-)
diff --git a/Ink Canvas/App.xaml.cs b/Ink Canvas/App.xaml.cs
index 0f50976a..3a953b57 100644
--- a/Ink Canvas/App.xaml.cs
+++ b/Ink Canvas/App.xaml.cs
@@ -331,7 +331,8 @@ namespace Ink_Canvas
private void CurrentDomain_ProcessExit(object sender, EventArgs e)
{
TimeSpan runDuration = DateTime.Now - appStartTime;
- WriteCrashLog($"应用程序退出,运行时长: {runDuration}");
+ string durationText = FormatTimeSpan(runDuration);
+ WriteCrashLog($"应用程序退出,运行时长: {durationText}");
// 如果有最后错误消息,记录到日志
if (!string.IsNullOrEmpty(lastErrorMessage))
@@ -340,6 +341,27 @@ namespace Ink_Canvas
}
}
+ // 新增:格式化时间跨度
+ private static string FormatTimeSpan(TimeSpan timeSpan)
+ {
+ if (timeSpan.TotalDays >= 1)
+ {
+ return $"{timeSpan.Days}天 {timeSpan.Hours}小时 {timeSpan.Minutes}分钟";
+ }
+ else if (timeSpan.TotalHours >= 1)
+ {
+ return $"{timeSpan.Hours}小时 {timeSpan.Minutes}分钟";
+ }
+ else if (timeSpan.TotalMinutes >= 1)
+ {
+ return $"{timeSpan.Minutes}分钟 {timeSpan.Seconds}秒";
+ }
+ else
+ {
+ return $"{timeSpan.Seconds}秒";
+ }
+ }
+
// 新增:记录崩溃日志
private static void WriteCrashLog(string message)
{
@@ -356,7 +378,7 @@ namespace Ink_Canvas
// 收集系统状态信息
string memoryUsage = (Process.GetCurrentProcess().WorkingSet64 / (1024 * 1024)) + " MB";
string cpuTime = Process.GetCurrentProcess().TotalProcessorTime.ToString();
- string processUptime = (DateTime.Now - Process.GetCurrentProcess().StartTime).ToString();
+ string processUptime = FormatTimeSpan(DateTime.Now - Process.GetCurrentProcess().StartTime);
string statusInfo = $"[内存: {memoryUsage}, CPU时间: {cpuTime}, 运行时长: {processUptime}]";
@@ -436,6 +458,9 @@ namespace Ink_Canvas
void App_Startup(object sender, StartupEventArgs e)
{
+ // 初始化应用启动时间
+ appStartTime = DateTime.Now;
+
/*if (!StoreHelper.IsStoreApp) */
RootPath = AppDomain.CurrentDomain.SetupInformation.ApplicationBase;
From e6354f724f388d6cc0eadec095b8d3307c5a151b Mon Sep 17 00:00:00 2001
From: CJKmkp <2564608840@qq.com>
Date: Sun, 24 Aug 2025 02:03:34 +0800
Subject: [PATCH 33/45] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=97=A5=E5=BF=97?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Ink Canvas/Helpers/InkFadeManager.cs | 54 +++----------------
.../MW_SimulatePressure&InkToShape.cs | 3 --
2 files changed, 6 insertions(+), 51 deletions(-)
diff --git a/Ink Canvas/Helpers/InkFadeManager.cs b/Ink Canvas/Helpers/InkFadeManager.cs
index df935494..1a1e6b49 100644
--- a/Ink Canvas/Helpers/InkFadeManager.cs
+++ b/Ink Canvas/Helpers/InkFadeManager.cs
@@ -64,17 +64,13 @@ namespace Ink_Canvas.Helpers
/// 抬笔点
public void AddFadingStroke(Stroke stroke, Point startPoint, Point endPoint)
{
- LogHelper.WriteLogToFile($"AddFadingStroke 被调用,IsEnabled: {IsEnabled}, stroke: {(stroke != null ? "非空" : "空")}", LogHelper.LogType.Info);
-
if (!IsEnabled || stroke == null)
{
- LogHelper.WriteLogToFile($"AddFadingStroke 被拒绝,IsEnabled: {IsEnabled}, stroke: {(stroke != null ? "非空" : "空")}", LogHelper.LogType.Warning);
return;
}
try
{
- LogHelper.WriteLogToFile($"开始添加渐隐墨迹,渐隐时间:{FadeTime}ms,动画时间:{AnimationDuration}ms", LogHelper.LogType.Info);
// 记录墨迹的起点和终点
_strokeStartPoints[stroke] = startPoint;
@@ -94,7 +90,6 @@ namespace Ink_Canvas.Helpers
timer.Tick += (sender, e) =>
{
- LogHelper.WriteLogToFile("定时器触发,开始渐隐动画", LogHelper.LogType.Info);
StartFadeAnimation(stroke);
timer.Stop();
_fadeTimers.Remove(stroke);
@@ -103,8 +98,6 @@ namespace Ink_Canvas.Helpers
_fadeTimers[stroke] = timer;
timer.Start();
- LogHelper.WriteLogToFile($"定时器已启动,将在 {FadeTime}ms 后开始渐隐", LogHelper.LogType.Info);
-
// 将视觉元素添加到画布上
_dispatcher.InvokeAsync(() =>
{
@@ -118,13 +111,11 @@ namespace Ink_Canvas.Helpers
if (parent != null)
{
parent.Children.Add(strokeVisual);
- LogHelper.WriteLogToFile("墨迹已添加到父容器", LogHelper.LogType.Info);
}
else
{
// 如果无法获取父容器,则添加到 inkCanvas.Children
_mainWindow.inkCanvas.Children.Add(strokeVisual);
- LogHelper.WriteLogToFile("墨迹已添加到 inkCanvas.Children", LogHelper.LogType.Info);
}
}
}
@@ -291,17 +282,12 @@ namespace Ink_Canvas.Helpers
{
try
{
- LogHelper.WriteLogToFile("开始创建墨迹视觉元素", LogHelper.LogType.Info);
-
// 创建路径几何,使用墨迹的实际位置
var geometry = stroke.GetGeometry();
if (geometry == null)
{
- LogHelper.WriteLogToFile("墨迹几何为空,无法创建视觉元素", LogHelper.LogType.Error);
return null;
}
-
- LogHelper.WriteLogToFile($"墨迹几何边界:{geometry.Bounds}", LogHelper.LogType.Info);
// 获取绘画属性
var drawingAttribs = stroke.DrawingAttributes;
@@ -334,14 +320,12 @@ namespace Ink_Canvas.Helpers
path.StrokeEndLineCap = PenLineCap.Flat;
path.StrokeLineJoin = PenLineJoin.Miter;
- // 高亮笔通常需要更宽的笔触来覆盖下面的内容
- if (drawingAttribs.Width < 20)
- {
- path.StrokeThickness = Math.Max(drawingAttribs.Width * 1.5, 20);
- }
-
- LogHelper.WriteLogToFile($"高亮笔特殊处理:透明度={path.Opacity},笔触宽度={path.StrokeThickness}", LogHelper.LogType.Info);
- }
+ // 高亮笔通常需要更宽的笔触来覆盖下面的内容
+ if (drawingAttribs.Width < 20)
+ {
+ path.StrokeThickness = Math.Max(drawingAttribs.Width * 1.5, 20);
+ }
+ }
// 不设置任何变换,保持墨迹原有粗细
var bounds = geometry.Bounds;
@@ -350,13 +334,10 @@ namespace Ink_Canvas.Helpers
System.Windows.Controls.Canvas.SetLeft(path, bounds.Left);
System.Windows.Controls.Canvas.SetTop(path, bounds.Top);
- LogHelper.WriteLogToFile($"墨迹视觉元素创建完成,位置:({bounds.Left}, {bounds.Top}),大小:{bounds.Width} x {bounds.Height},粗细:{drawingAttribs.Width},高亮笔:{drawingAttribs.IsHighlighter}", LogHelper.LogType.Info);
-
return path;
}
catch (Exception ex)
{
- LogHelper.WriteLogToFile($"创建墨迹视觉元素失败: {ex}", LogHelper.LogType.Error);
return null;
}
}
@@ -371,8 +352,6 @@ namespace Ink_Canvas.Helpers
try
{
- LogHelper.WriteLogToFile("开始执行渐隐动画", LogHelper.LogType.Info);
-
_dispatcher.InvokeAsync(() =>
{
// 获取当前透明度和判断是否为高亮笔
@@ -403,7 +382,6 @@ namespace Ink_Canvas.Helpers
{
try
{
- LogHelper.WriteLogToFile("开始普通墨迹渐进式渐隐动画", LogHelper.LogType.Info);
StartProgressiveFadeAnimation(visual, stroke, currentOpacity, AnimationDuration);
}
catch (Exception ex)
@@ -419,7 +397,6 @@ namespace Ink_Canvas.Helpers
{
try
{
- LogHelper.WriteLogToFile("开始高亮笔渐进式渐隐动画", LogHelper.LogType.Info);
StartProgressiveFadeAnimation(visual, stroke, currentOpacity, (int)(AnimationDuration * 1.5));
}
catch (Exception ex)
@@ -435,8 +412,6 @@ namespace Ink_Canvas.Helpers
{
try
{
- LogHelper.WriteLogToFile($"开始渐进式渐隐动画,墨迹点数:{stroke.StylusPoints.Count}", LogHelper.LogType.Info);
-
// 确保所有墨迹都能显示动画,包括短墨迹
if (stroke.StylusPoints.Count < 2)
{
@@ -474,8 +449,6 @@ namespace Ink_Canvas.Helpers
segmentCount = Math.Max(segmentCount, 4);
var pointsPerSegment = Math.Max(1, totalPoints / segmentCount);
-
- LogHelper.WriteLogToFile($"创建 {segmentCount} 个分段,每段约 {pointsPerSegment} 个点", LogHelper.LogType.Info);
// 隐藏原始视觉元素
originalVisual.Visibility = Visibility.Hidden;
@@ -527,7 +500,6 @@ namespace Ink_Canvas.Helpers
}
catch (Exception ex)
{
- LogHelper.WriteLogToFile($"创建分段墨迹失败: {ex}", LogHelper.LogType.Error);
StartSimpleFadeAnimation(originalVisual, stroke, opacity, duration);
}
}
@@ -582,7 +554,6 @@ namespace Ink_Canvas.Helpers
}
catch (Exception ex)
{
- LogHelper.WriteLogToFile($"创建墨迹分段失败: {ex}", LogHelper.LogType.Error);
return null;
}
}
@@ -594,8 +565,6 @@ namespace Ink_Canvas.Helpers
{
try
{
- LogHelper.WriteLogToFile($"开始 {segments.Count} 个分段的渐隐动画", LogHelper.LogType.Info);
-
// 动画时序算法
var segmentDuration = CalculateOptimalSegmentDuration(totalDuration, segments.Count);
var animationCurve = CreateAppleStyleAnimationCurve(segments.Count, totalDuration);
@@ -627,12 +596,10 @@ namespace Ink_Canvas.Helpers
lock (completedSegments)
{
completedSegments.Add(segment);
- LogHelper.WriteLogToFile($"分段 {segmentIndex} 动画完成,已完成 {completedSegments.Count}/{totalSegments}", LogHelper.LogType.Info);
// 检查是否所有分段都完成了
if (completedSegments.Count >= totalSegments)
{
- LogHelper.WriteLogToFile("所有分段动画完成,开始清理", LogHelper.LogType.Info);
CleanupSegmentedAnimation(segments, originalStroke, originalVisual);
}
}
@@ -652,7 +619,6 @@ namespace Ink_Canvas.Helpers
safetyTimer.Tick += (sender, e) =>
{
- LogHelper.WriteLogToFile($"安全超时触发,强制清理动画", LogHelper.LogType.Warning);
CleanupSegmentedAnimation(segments, originalStroke, originalVisual);
safetyTimer.Stop();
};
@@ -709,8 +675,6 @@ namespace Ink_Canvas.Helpers
{
try
{
- LogHelper.WriteLogToFile("清理分段渐隐动画", LogHelper.LogType.Info);
-
// 移除所有分段
var parent = _mainWindow.inkCanvas?.Parent as System.Windows.Controls.Panel;
@@ -742,8 +706,6 @@ namespace Ink_Canvas.Helpers
{
try
{
- LogHelper.WriteLogToFile("使用简单渐隐动画", LogHelper.LogType.Info);
-
var fadeAnimation = new DoubleAnimation
{
From = currentOpacity,
@@ -848,19 +810,15 @@ namespace Ink_Canvas.Helpers
{
try
{
- LogHelper.WriteLogToFile("渐隐动画完成,开始清理墨迹", LogHelper.LogType.Info);
-
// 从父容器中移除墨迹
var parent = _mainWindow.inkCanvas?.Parent as System.Windows.Controls.Panel;
if (parent != null && parent.Children.Contains(visual))
{
parent.Children.Remove(visual);
- LogHelper.WriteLogToFile("墨迹已从父容器移除", LogHelper.LogType.Info);
}
else if (_mainWindow.inkCanvas != null && _mainWindow.inkCanvas.Children.Contains(visual))
{
_mainWindow.inkCanvas.Children.Remove(visual);
- LogHelper.WriteLogToFile("墨迹已从 inkCanvas.Children 移除", LogHelper.LogType.Info);
}
RemoveStroke(stroke);
diff --git a/Ink Canvas/MainWindow_cs/MW_SimulatePressure&InkToShape.cs b/Ink Canvas/MainWindow_cs/MW_SimulatePressure&InkToShape.cs
index 4a6c108f..e25bb882 100644
--- a/Ink Canvas/MainWindow_cs/MW_SimulatePressure&InkToShape.cs
+++ b/Ink Canvas/MainWindow_cs/MW_SimulatePressure&InkToShape.cs
@@ -59,8 +59,6 @@ namespace Ink_Canvas
// 检查是否启用墨迹渐隐功能
if (Settings.Canvas.EnableInkFade)
{
- LogHelper.WriteLogToFile("StrokeCollected: 进入墨迹渐隐模式", LogHelper.LogType.Info);
-
// 获取墨迹的起点和终点
var startPoint = e.Stroke.StylusPoints.Count > 0 ? e.Stroke.StylusPoints[0].ToPoint() : new Point();
var endPoint = e.Stroke.StylusPoints.Count > 0 ? e.Stroke.StylusPoints[e.Stroke.StylusPoints.Count - 1].ToPoint() : new Point();
@@ -75,7 +73,6 @@ namespace Ink_Canvas
if (_inkFadeManager != null)
{
_inkFadeManager.AddFadingStroke(e.Stroke, startPoint, endPoint);
- LogHelper.WriteLogToFile($"StrokeCollected: 墨迹已添加到渐隐管理器,起点:{startPoint},终点:{endPoint}", LogHelper.LogType.Info);
}
else
{
From 365459f64957394d51b0b6d367c80c6491d76a8d Mon Sep 17 00:00:00 2001
From: CJKmkp <2564608840@qq.com>
Date: Sun, 24 Aug 2025 02:27:57 +0800
Subject: [PATCH 34/45] =?UTF-8?q?improve:=E5=BF=AB=E6=8D=B7=E9=94=AE?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Ink Canvas/Helpers/GlobalHotkeyManager.cs | 314 +++++++++++++++++-
Ink Canvas/HotkeyConfig.json | 96 ++++++
Ink Canvas/Windows/HotkeyItem.xaml.cs | 7 +-
.../Windows/HotkeySettingsWindow.xaml.cs | 47 ++-
4 files changed, 456 insertions(+), 8 deletions(-)
create mode 100644 Ink Canvas/HotkeyConfig.json
diff --git a/Ink Canvas/Helpers/GlobalHotkeyManager.cs b/Ink Canvas/Helpers/GlobalHotkeyManager.cs
index 4ab1a459..cb5a1d21 100644
--- a/Ink Canvas/Helpers/GlobalHotkeyManager.cs
+++ b/Ink Canvas/Helpers/GlobalHotkeyManager.cs
@@ -1,6 +1,8 @@
using System;
using System.Collections.Generic;
using System.Windows.Input;
+using System.IO;
+using Newtonsoft.Json;
using NHotkey.Wpf;
namespace Ink_Canvas.Helpers
@@ -14,6 +16,10 @@ namespace Ink_Canvas.Helpers
private readonly Dictionary _registeredHotkeys;
private readonly MainWindow _mainWindow;
private bool _isDisposed = false;
+
+ // 配置文件路径
+ private static readonly string HotkeyConfigFile = Path.Combine(App.RootPath, "HotkeyConfig.json");
+ private static readonly string HotkeyConfigBackupFile = Path.Combine(App.RootPath, "HotkeyConfig.json.bak");
#endregion
#region Constructor
@@ -207,13 +213,28 @@ namespace Ink_Canvas.Helpers
{
try
{
- // 这里可以从配置文件或设置中加载自定义快捷键
- // 暂时使用默认快捷键
- RegisterDefaultHotkeys();
+ LogHelper.WriteLogToFile("开始从配置文件加载快捷键设置", LogHelper.LogType.Event);
+
+ // 先注销所有现有快捷键
+ UnregisterAllHotkeys();
+
+ // 尝试从配置文件加载
+ if (LoadHotkeysFromConfigFile())
+ {
+ LogHelper.WriteLogToFile("成功从配置文件加载快捷键设置", LogHelper.LogType.Event);
+ }
+ else
+ {
+ // 如果配置文件不存在或加载失败,使用默认快捷键
+ LogHelper.WriteLogToFile("配置文件不存在或加载失败,使用默认快捷键", LogHelper.LogType.Warning);
+ RegisterDefaultHotkeys();
+ }
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"从设置加载快捷键时出错: {ex.Message}", LogHelper.LogType.Error);
+ // 出错时使用默认快捷键
+ RegisterDefaultHotkeys();
}
}
@@ -224,14 +245,64 @@ namespace Ink_Canvas.Helpers
{
try
{
- // 这里可以将快捷键配置保存到配置文件或设置中
- LogHelper.WriteLogToFile("快捷键配置已保存", LogHelper.LogType.Event);
+ LogHelper.WriteLogToFile("开始保存快捷键配置到配置文件", LogHelper.LogType.Event);
+
+ if (SaveHotkeysToConfigFile())
+ {
+ LogHelper.WriteLogToFile("快捷键配置已成功保存到配置文件", LogHelper.LogType.Event);
+ }
+ else
+ {
+ LogHelper.WriteLogToFile("保存快捷键配置失败", LogHelper.LogType.Error);
+ }
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"保存快捷键配置时出错: {ex.Message}", LogHelper.LogType.Error);
}
}
+
+ ///
+ /// 更新快捷键配置
+ ///
+ /// 快捷键名称
+ /// 新按键
+ /// 新修饰键
+ /// 是否更新成功
+ public bool UpdateHotkey(string hotkeyName, Key key, ModifierKeys modifiers)
+ {
+ try
+ {
+ if (!_registeredHotkeys.ContainsKey(hotkeyName))
+ {
+ LogHelper.WriteLogToFile($"快捷键 {hotkeyName} 不存在,无法更新", LogHelper.LogType.Warning);
+ return false;
+ }
+
+ // 获取原有的动作
+ var originalAction = _registeredHotkeys[hotkeyName].Action;
+
+ // 注销原有快捷键
+ UnregisterHotkey(hotkeyName);
+
+ // 注册新的快捷键
+ var success = RegisterHotkey(hotkeyName, key, modifiers, originalAction);
+
+ if (success)
+ {
+ LogHelper.WriteLogToFile($"成功更新快捷键 {hotkeyName}: {modifiers}+{key}", LogHelper.LogType.Event);
+ // 自动保存配置
+ SaveHotkeysToSettings();
+ }
+
+ return success;
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"更新快捷键 {hotkeyName} 时出错: {ex.Message}", LogHelper.LogType.Error);
+ return false;
+ }
+ }
#endregion
#region Private Helper Methods
@@ -266,6 +337,219 @@ namespace Ink_Canvas.Helpers
LogHelper.WriteLogToFile($"切换到笔类型{penTypeIndex}时出错: {ex.Message}", LogHelper.LogType.Error);
}
}
+
+ ///
+ /// 从配置文件加载快捷键设置
+ ///
+ /// 是否加载成功
+ private bool LoadHotkeysFromConfigFile()
+ {
+ try
+ {
+ if (!File.Exists(HotkeyConfigFile))
+ {
+ LogHelper.WriteLogToFile($"快捷键配置文件不存在: {HotkeyConfigFile}", LogHelper.LogType.Warning);
+ return false;
+ }
+
+ // 读取配置文件内容
+ string jsonContent = File.ReadAllText(HotkeyConfigFile, System.Text.Encoding.UTF8);
+ if (string.IsNullOrEmpty(jsonContent))
+ {
+ LogHelper.WriteLogToFile("快捷键配置文件为空", LogHelper.LogType.Warning);
+ return false;
+ }
+
+ // 反序列化配置
+ var config = JsonConvert.DeserializeObject(jsonContent);
+ if (config?.Hotkeys == null || config.Hotkeys.Count == 0)
+ {
+ LogHelper.WriteLogToFile("快捷键配置为空或格式错误", LogHelper.LogType.Warning);
+ return false;
+ }
+
+ // 注册配置中的快捷键
+ int successCount = 0;
+ foreach (var hotkeyConfig in config.Hotkeys)
+ {
+ try
+ {
+ // 根据快捷键名称获取对应的动作
+ var action = GetActionByName(hotkeyConfig.Name);
+ if (action != null)
+ {
+ if (RegisterHotkey(hotkeyConfig.Name, hotkeyConfig.Key, hotkeyConfig.Modifiers, action))
+ {
+ successCount++;
+ }
+ }
+ else
+ {
+ LogHelper.WriteLogToFile($"未找到快捷键 {hotkeyConfig.Name} 对应的动作", LogHelper.LogType.Warning);
+ }
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"注册快捷键 {hotkeyConfig.Name} 时出错: {ex.Message}", LogHelper.LogType.Error);
+ }
+ }
+
+ LogHelper.WriteLogToFile($"成功加载 {successCount}/{config.Hotkeys.Count} 个快捷键配置", LogHelper.LogType.Event);
+ return successCount > 0;
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"从配置文件加载快捷键时出错: {ex.Message}", LogHelper.LogType.Error);
+
+ // 尝试从备份文件加载
+ if (File.Exists(HotkeyConfigBackupFile))
+ {
+ LogHelper.WriteLogToFile("尝试从备份文件加载快捷键配置", LogHelper.LogType.Warning);
+ try
+ {
+ string backupContent = File.ReadAllText(HotkeyConfigBackupFile, System.Text.Encoding.UTF8);
+ var backupConfig = JsonConvert.DeserializeObject(backupContent);
+ if (backupConfig?.Hotkeys != null && backupConfig.Hotkeys.Count > 0)
+ {
+ // 恢复备份文件
+ File.Copy(HotkeyConfigBackupFile, HotkeyConfigFile, true);
+ LogHelper.WriteLogToFile("已从备份文件恢复快捷键配置", LogHelper.LogType.Event);
+ return LoadHotkeysFromConfigFile();
+ }
+ }
+ catch (Exception backupEx)
+ {
+ LogHelper.WriteLogToFile($"从备份文件加载快捷键配置时出错: {backupEx.Message}", LogHelper.LogType.Error);
+ }
+ }
+
+ return false;
+ }
+ }
+
+ ///
+ /// 保存快捷键配置到配置文件
+ ///
+ /// 是否保存成功
+ private bool SaveHotkeysToConfigFile()
+ {
+ try
+ {
+ // 确保配置目录存在
+ string configDir = Path.GetDirectoryName(HotkeyConfigFile);
+ if (!Directory.Exists(configDir))
+ {
+ Directory.CreateDirectory(configDir);
+ }
+
+ // 创建配置对象
+ var config = new HotkeyConfig
+ {
+ Version = "1.0",
+ LastModified = DateTime.Now,
+ Hotkeys = new List()
+ };
+
+ // 添加所有已注册的快捷键
+ foreach (var hotkey in _registeredHotkeys.Values)
+ {
+ config.Hotkeys.Add(new HotkeyConfigItem
+ {
+ Name = hotkey.Name,
+ Key = hotkey.Key,
+ Modifiers = hotkey.Modifiers
+ });
+ }
+
+ // 序列化为JSON
+ var settings = new JsonSerializerSettings
+ {
+ Formatting = Formatting.Indented
+ };
+
+ string jsonContent = JsonConvert.SerializeObject(config, settings);
+
+ // 先写入临时文件,然后替换原文件(原子操作)
+ string tempFile = HotkeyConfigFile + ".temp";
+ File.WriteAllText(tempFile, jsonContent, System.Text.Encoding.UTF8);
+
+ // 如果原文件存在,先备份
+ if (File.Exists(HotkeyConfigFile))
+ {
+ File.Copy(HotkeyConfigFile, HotkeyConfigBackupFile, true);
+ }
+
+ // 替换原文件
+ File.Move(tempFile, HotkeyConfigFile);
+
+ LogHelper.WriteLogToFile($"快捷键配置已保存到: {HotkeyConfigFile}", LogHelper.LogType.Event);
+ return true;
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"保存快捷键配置到配置文件时出错: {ex.Message}", LogHelper.LogType.Error);
+ return false;
+ }
+ }
+
+ ///
+ /// 根据快捷键名称获取对应的动作
+ ///
+ /// 快捷键名称
+ /// 对应的动作,如果不存在则返回null
+ private Action GetActionByName(string hotkeyName)
+ {
+ try
+ {
+ switch (hotkeyName)
+ {
+ case "Undo":
+ return () => _mainWindow.SymbolIconUndo_MouseUp(null, null);
+ case "Redo":
+ return () => _mainWindow.SymbolIconRedo_MouseUp(null, null);
+ case "Clear":
+ return () => _mainWindow.SymbolIconDelete_MouseUp(null, null);
+ case "Paste":
+ return () => _mainWindow.HandleGlobalPaste(null, null);
+ case "SelectTool":
+ return () => _mainWindow.SymbolIconSelect_MouseUp(null, null);
+ case "DrawTool":
+ return () => _mainWindow.PenIcon_Click(null, null);
+ case "EraserTool":
+ return () => _mainWindow.EraserIcon_Click(null, null);
+ case "BlackboardTool":
+ return () => _mainWindow.ImageBlackboard_MouseUp(null, null);
+ case "QuitDrawTool":
+ return () => _mainWindow.CursorIcon_Click(null, null);
+ case "Pen1":
+ return () => SwitchToPenType(0);
+ case "Pen2":
+ return () => SwitchToPenType(1);
+ case "Pen3":
+ return () => SwitchToPenType(2);
+ case "Pen4":
+ return () => SwitchToPenType(3);
+ case "Pen5":
+ return () => SwitchToPenType(4);
+ case "DrawLine":
+ return () => _mainWindow.BtnDrawLine_Click(null, null);
+ case "Screenshot":
+ return () => _mainWindow.SaveScreenShotToDesktop();
+ case "Hide":
+ return () => _mainWindow.SymbolIconEmoji_MouseUp(null, null);
+ case "Exit":
+ return () => _mainWindow.KeyExit(null, null);
+ default:
+ LogHelper.WriteLogToFile($"未知的快捷键名称: {hotkeyName}", LogHelper.LogType.Warning);
+ return null;
+ }
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"获取快捷键 {hotkeyName} 对应动作时出错: {ex.Message}", LogHelper.LogType.Error);
+ return null;
+ }
+ }
#endregion
#region IDisposable Implementation
@@ -296,6 +580,26 @@ namespace Ink_Canvas.Helpers
return $"{modifiersText}{Key}";
}
}
+
+ ///
+ /// 快捷键配置类
+ ///
+ private class HotkeyConfig
+ {
+ public string Version { get; set; }
+ public DateTime LastModified { get; set; }
+ public List Hotkeys { get; set; }
+ }
+
+ ///
+ /// 快捷键配置项类
+ ///
+ private class HotkeyConfigItem
+ {
+ public string Name { get; set; }
+ public Key Key { get; set; }
+ public ModifierKeys Modifiers { get; set; }
+ }
#endregion
}
}
\ No newline at end of file
diff --git a/Ink Canvas/HotkeyConfig.json b/Ink Canvas/HotkeyConfig.json
new file mode 100644
index 00000000..4ce2d1ee
--- /dev/null
+++ b/Ink Canvas/HotkeyConfig.json
@@ -0,0 +1,96 @@
+{
+ "Version": "1.0",
+ "LastModified": "2025-01-28T15:30:00",
+ "Hotkeys": [
+ {
+ "Name": "Undo",
+ "Key": "Z",
+ "Modifiers": "Control"
+ },
+ {
+ "Name": "Redo",
+ "Key": "Y",
+ "Modifiers": "Control"
+ },
+ {
+ "Name": "Clear",
+ "Key": "E",
+ "Modifiers": "Control"
+ },
+ {
+ "Name": "Paste",
+ "Key": "V",
+ "Modifiers": "Control"
+ },
+ {
+ "Name": "SelectTool",
+ "Key": "S",
+ "Modifiers": "Alt"
+ },
+ {
+ "Name": "DrawTool",
+ "Key": "D",
+ "Modifiers": "Alt"
+ },
+ {
+ "Name": "EraserTool",
+ "Key": "E",
+ "Modifiers": "Alt"
+ },
+ {
+ "Name": "BlackboardTool",
+ "Key": "B",
+ "Modifiers": "Alt"
+ },
+ {
+ "Name": "QuitDrawTool",
+ "Key": "Q",
+ "Modifiers": "Alt"
+ },
+ {
+ "Name": "Pen1",
+ "Key": "D1",
+ "Modifiers": "Alt"
+ },
+ {
+ "Name": "Pen2",
+ "Key": "D2",
+ "Modifiers": "Alt"
+ },
+ {
+ "Name": "Pen3",
+ "Key": "D3",
+ "Modifiers": "Alt"
+ },
+ {
+ "Name": "Pen4",
+ "Key": "D4",
+ "Modifiers": "Alt"
+ },
+ {
+ "Name": "Pen5",
+ "Key": "D5",
+ "Modifiers": "Alt"
+ },
+ {
+ "Name": "DrawLine",
+ "Key": "L",
+ "Modifiers": "Alt"
+ },
+ {
+ "Name": "Screenshot",
+ "Key": "C",
+ "Modifiers": "Alt"
+ },
+ {
+ "Name": "Hide",
+ "Key": "V",
+ "Modifiers": "Alt"
+ },
+ {
+ "Name": "Exit",
+ "Key": "Escape",
+ "Modifiers": "None"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/Ink Canvas/Windows/HotkeyItem.xaml.cs b/Ink Canvas/Windows/HotkeyItem.xaml.cs
index 3ff70c8c..4f498877 100644
--- a/Ink Canvas/Windows/HotkeyItem.xaml.cs
+++ b/Ink Canvas/Windows/HotkeyItem.xaml.cs
@@ -32,6 +32,11 @@ namespace Ink_Canvas.Windows
public string DefaultKey { get; set; }
public string DefaultModifiers { get; set; }
+
+ ///
+ /// 快捷键名称(用于标识,如"Undo")
+ ///
+ public string HotkeyName { get; set; }
private Key _currentKey = Key.None;
private ModifierKeys _currentModifiers = ModifierKeys.None;
@@ -144,7 +149,7 @@ namespace Ink_Canvas.Windows
// 触发快捷键变更事件
HotkeyChanged?.Invoke(this, new HotkeyChangedEventArgs
{
- HotkeyName = Title,
+ HotkeyName = HotkeyName ?? Title, // 优先使用HotkeyName,如果没有则使用Title
Key = _currentKey,
Modifiers = _currentModifiers
});
diff --git a/Ink Canvas/Windows/HotkeySettingsWindow.xaml.cs b/Ink Canvas/Windows/HotkeySettingsWindow.xaml.cs
index 453122cb..1d3c30dc 100644
--- a/Ink Canvas/Windows/HotkeySettingsWindow.xaml.cs
+++ b/Ink Canvas/Windows/HotkeySettingsWindow.xaml.cs
@@ -39,25 +39,60 @@ namespace Ink_Canvas.Windows
#region Private Methods
private void InitializeHotkeyItems()
{
- // 初始化快捷键项
+ // 初始化快捷键项并设置HotkeyName
_hotkeyItems["Undo"] = UndoHotkey;
+ UndoHotkey.HotkeyName = "Undo";
+
_hotkeyItems["Redo"] = RedoHotkey;
+ RedoHotkey.HotkeyName = "Redo";
+
_hotkeyItems["Clear"] = ClearHotkey;
+ ClearHotkey.HotkeyName = "Clear";
+
_hotkeyItems["Paste"] = PasteHotkey;
+ PasteHotkey.HotkeyName = "Paste";
+
_hotkeyItems["SelectTool"] = SelectToolHotkey;
+ SelectToolHotkey.HotkeyName = "SelectTool";
+
_hotkeyItems["DrawTool"] = DrawToolHotkey;
+ DrawToolHotkey.HotkeyName = "DrawTool";
+
_hotkeyItems["EraserTool"] = EraserToolHotkey;
+ EraserToolHotkey.HotkeyName = "EraserTool";
+
_hotkeyItems["BlackboardTool"] = BlackboardToolHotkey;
+ BlackboardToolHotkey.HotkeyName = "BlackboardTool";
+
_hotkeyItems["QuitDrawTool"] = QuitDrawToolHotkey;
+ QuitDrawToolHotkey.HotkeyName = "QuitDrawTool";
+
_hotkeyItems["Pen1"] = Pen1Hotkey;
+ Pen1Hotkey.HotkeyName = "Pen1";
+
_hotkeyItems["Pen2"] = Pen2Hotkey;
+ Pen2Hotkey.HotkeyName = "Pen2";
+
_hotkeyItems["Pen3"] = Pen3Hotkey;
+ Pen3Hotkey.HotkeyName = "Pen3";
+
_hotkeyItems["Pen4"] = Pen4Hotkey;
+ Pen4Hotkey.HotkeyName = "Pen4";
+
_hotkeyItems["Pen5"] = Pen5Hotkey;
+ Pen5Hotkey.HotkeyName = "Pen5";
+
_hotkeyItems["DrawLine"] = DrawLineHotkey;
+ DrawLineHotkey.HotkeyName = "DrawLine";
+
_hotkeyItems["Screenshot"] = ScreenshotHotkey;
+ ScreenshotHotkey.HotkeyName = "Screenshot";
+
_hotkeyItems["Hide"] = HideHotkey;
+ HideHotkey.HotkeyName = "Hide";
+
_hotkeyItems["Exit"] = ExitHotkey;
+ ExitHotkey.HotkeyName = "Exit";
}
private void LoadCurrentHotkeys()
@@ -132,7 +167,15 @@ namespace Ink_Canvas.Windows
var action = GetActionForHotkey(hotkeyName);
if (action != null)
{
- _hotkeyManager.RegisterHotkey(hotkeyName, key, modifiers, action);
+ // 使用快捷键管理器的UpdateHotkey方法,这会自动保存配置
+ if (_hotkeyManager.UpdateHotkey(hotkeyName, key, modifiers))
+ {
+ LogHelper.WriteLogToFile($"快捷键 {hotkeyName} 已更新为 {modifiers}+{key} 并自动保存", LogHelper.LogType.Event);
+ }
+ else
+ {
+ LogHelper.WriteLogToFile($"更新快捷键 {hotkeyName} 失败", LogHelper.LogType.Error);
+ }
}
}
catch (Exception ex)
From b7c52842f288d4a5690f55608e0efa8257a69204 Mon Sep 17 00:00:00 2001
From: CJKmkp <2564608840@qq.com>
Date: Sun, 24 Aug 2025 02:30:38 +0800
Subject: [PATCH 35/45] =?UTF-8?q?improve:=E5=BF=AB=E6=8D=B7=E9=94=AE?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Ink Canvas/Helpers/GlobalHotkeyManager.cs | 45 +++++++++++++++++++++++
1 file changed, 45 insertions(+)
diff --git a/Ink Canvas/Helpers/GlobalHotkeyManager.cs b/Ink Canvas/Helpers/GlobalHotkeyManager.cs
index cb5a1d21..91923e38 100644
--- a/Ink Canvas/Helpers/GlobalHotkeyManager.cs
+++ b/Ink Canvas/Helpers/GlobalHotkeyManager.cs
@@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.Windows.Input;
using System.IO;
+using System.Reflection;
using Newtonsoft.Json;
using NHotkey.Wpf;
@@ -66,6 +67,13 @@ namespace Ink_Canvas.Helpers
{
try
{
+ // 检查是否处于选择模式,如果是则不拦截键盘操作
+ if (IsInSelectMode())
+ {
+ LogHelper.WriteLogToFile($"快捷键 {hotkeyName} 在选择模式下被忽略", LogHelper.LogType.Info);
+ return;
+ }
+
// 确保在主线程中执行
_mainWindow.Dispatcher.Invoke(() =>
{
@@ -550,6 +558,43 @@ namespace Ink_Canvas.Helpers
return null;
}
}
+
+ ///
+ /// 检查当前是否处于选择模式
+ ///
+ /// 如果处于选择模式则返回true,否则返回false
+ private bool IsInSelectMode()
+ {
+ try
+ {
+ // 通过反射访问主窗口的inkCanvas属性
+ var inkCanvasProperty = _mainWindow.GetType().GetProperty("inkCanvas",
+ BindingFlags.NonPublic | BindingFlags.Instance);
+
+ if (inkCanvasProperty != null)
+ {
+ var inkCanvas = inkCanvasProperty.GetValue(_mainWindow);
+ if (inkCanvas != null)
+ {
+ // 通过反射访问EditingMode属性
+ var editingModeProperty = inkCanvas.GetType().GetProperty("EditingMode");
+ if (editingModeProperty != null)
+ {
+ var editingMode = editingModeProperty.GetValue(inkCanvas);
+ // 检查是否为选择模式
+ return editingMode != null && editingMode.ToString() == "Select";
+ }
+ }
+ }
+
+ return false;
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"检查选择模式状态时出错: {ex.Message}", LogHelper.LogType.Warning);
+ return false;
+ }
+ }
#endregion
#region IDisposable Implementation
From ff9ce4df4487a67f920f926d5494311eba57f210 Mon Sep 17 00:00:00 2001
From: CJKmkp <2564608840@qq.com>
Date: Sun, 24 Aug 2025 08:45:53 +0800
Subject: [PATCH 36/45] =?UTF-8?q?imrpove:=E5=BF=AB=E6=8D=B7=E9=94=AE?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Ink Canvas/Helpers/GlobalHotkeyManager.cs | 257 +++++++++++++++---
.../MainWindow_cs/MW_FloatingBarIcons.cs | 100 +++++++
2 files changed, 319 insertions(+), 38 deletions(-)
diff --git a/Ink Canvas/Helpers/GlobalHotkeyManager.cs b/Ink Canvas/Helpers/GlobalHotkeyManager.cs
index 91923e38..82cb01c9 100644
--- a/Ink Canvas/Helpers/GlobalHotkeyManager.cs
+++ b/Ink Canvas/Helpers/GlobalHotkeyManager.cs
@@ -17,6 +17,7 @@ namespace Ink_Canvas.Helpers
private readonly Dictionary _registeredHotkeys;
private readonly MainWindow _mainWindow;
private bool _isDisposed = false;
+ private bool _hotkeysShouldBeRegistered = true; // 跟踪快捷键是否应该被注册
// 配置文件路径
private static readonly string HotkeyConfigFile = Path.Combine(App.RootPath, "HotkeyConfig.json");
@@ -28,6 +29,7 @@ namespace Ink_Canvas.Helpers
{
_mainWindow = mainWindow ?? throw new ArgumentNullException(nameof(mainWindow));
_registeredHotkeys = new Dictionary();
+ _hotkeysShouldBeRegistered = false; // 启动时不注册热键,等待需要时再注册
}
#endregion
@@ -67,13 +69,6 @@ namespace Ink_Canvas.Helpers
{
try
{
- // 检查是否处于选择模式,如果是则不拦截键盘操作
- if (IsInSelectMode())
- {
- LogHelper.WriteLogToFile($"快捷键 {hotkeyName} 在选择模式下被忽略", LogHelper.LogType.Info);
- return;
- }
-
// 确保在主线程中执行
_mainWindow.Dispatcher.Invoke(() =>
{
@@ -87,7 +82,7 @@ namespace Ink_Canvas.Helpers
});
_registeredHotkeys[hotkeyName] = hotkeyInfo;
- LogHelper.WriteLogToFile($"成功注册全局快捷键: {hotkeyName} ({modifiers}+{key})", LogHelper.LogType.Event);
+ // 成功注册全局快捷键
return true;
}
catch (Exception ex)
@@ -111,7 +106,7 @@ namespace Ink_Canvas.Helpers
HotkeyManager.Current.Remove(hotkeyName);
_registeredHotkeys.Remove(hotkeyName);
- LogHelper.WriteLogToFile($"成功注销全局快捷键: {hotkeyName}", LogHelper.LogType.Event);
+ // 成功注销全局快捷键
return true;
}
catch (Exception ex)
@@ -144,7 +139,7 @@ namespace Ink_Canvas.Helpers
}
_registeredHotkeys.Clear();
- LogHelper.WriteLogToFile("已注销所有全局快捷键", LogHelper.LogType.Event);
+ // 已注销所有全局快捷键,集合已清空
}
catch (Exception ex)
{
@@ -178,6 +173,8 @@ namespace Ink_Canvas.Helpers
{
try
{
+ // 开始注册默认快捷键集合
+
// 基本操作快捷键
RegisterHotkey("Undo", Key.Z, ModifierKeys.Control, () => _mainWindow.SymbolIconUndo_MouseUp(null, null));
RegisterHotkey("Redo", Key.Y, ModifierKeys.Control, () => _mainWindow.SymbolIconRedo_MouseUp(null, null));
@@ -206,7 +203,7 @@ namespace Ink_Canvas.Helpers
// 退出快捷键
RegisterHotkey("Exit", Key.Escape, ModifierKeys.None, () => _mainWindow.KeyExit(null, null));
- LogHelper.WriteLogToFile("已注册默认全局快捷键集合", LogHelper.LogType.Event);
+ // 已注册默认全局快捷键集合
}
catch (Exception ex)
{
@@ -221,29 +218,34 @@ namespace Ink_Canvas.Helpers
{
try
{
- LogHelper.WriteLogToFile("开始从配置文件加载快捷键设置", LogHelper.LogType.Event);
+ // 开始从配置文件加载快捷键设置
- // 先注销所有现有快捷键
- UnregisterAllHotkeys();
+ // 检查是否应该注册快捷键
+ if (!_hotkeysShouldBeRegistered)
+ {
+ // 当前状态不允许注册快捷键,跳过加载
+ return;
+ }
// 尝试从配置文件加载
if (LoadHotkeysFromConfigFile())
{
- LogHelper.WriteLogToFile("成功从配置文件加载快捷键设置", LogHelper.LogType.Event);
+ // 成功从配置文件加载快捷键设置
+ _hotkeysShouldBeRegistered = true;
}
else
{
// 如果配置文件不存在或加载失败,使用默认快捷键
- LogHelper.WriteLogToFile("配置文件不存在或加载失败,使用默认快捷键", LogHelper.LogType.Warning);
RegisterDefaultHotkeys();
+ _hotkeysShouldBeRegistered = true;
}
}
- catch (Exception ex)
- {
- LogHelper.WriteLogToFile($"从设置加载快捷键时出错: {ex.Message}", LogHelper.LogType.Error);
- // 出错时使用默认快捷键
- RegisterDefaultHotkeys();
- }
+ catch (Exception ex)
+ {
+ // 出错时使用默认快捷键
+ RegisterDefaultHotkeys();
+ _hotkeysShouldBeRegistered = true;
+ }
}
///
@@ -270,6 +272,37 @@ namespace Ink_Canvas.Helpers
}
}
+ ///
+ /// 启用快捷键注册功能
+ /// 调用此方法后,快捷键将被允许注册
+ ///
+ public void EnableHotkeyRegistration()
+ {
+ try
+ {
+ if (!_hotkeysShouldBeRegistered)
+ {
+ _hotkeysShouldBeRegistered = true;
+
+ // 如果当前不在鼠标模式下,立即注册快捷键
+ var currentIsMouseMode = IsInSelectMode();
+
+ if (!currentIsMouseMode)
+ {
+ LoadHotkeysFromSettings();
+ }
+ }
+ else
+ {
+ // 快捷键注册功能已经启用
+ }
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"启用快捷键注册功能时出错: {ex.Message}", LogHelper.LogType.Error);
+ }
+ }
+
///
/// 更新快捷键配置
///
@@ -403,6 +436,10 @@ namespace Ink_Canvas.Helpers
}
LogHelper.WriteLogToFile($"成功加载 {successCount}/{config.Hotkeys.Count} 个快捷键配置", LogHelper.LogType.Event);
+ if (successCount > 0)
+ {
+ _hotkeysShouldBeRegistered = true;
+ }
return successCount > 0;
}
catch (Exception ex)
@@ -560,39 +597,183 @@ namespace Ink_Canvas.Helpers
}
///
- /// 检查当前是否处于选择模式
+ /// 检查当前是否处于鼠标模式(选择模式)
///
- /// 如果处于选择模式则返回true,否则返回false
+ /// 如果处于鼠标模式则返回true(不应该注册快捷键),否则返回false(应该注册快捷键)
private bool IsInSelectMode()
{
try
{
- // 通过反射访问主窗口的inkCanvas属性
- var inkCanvasProperty = _mainWindow.GetType().GetProperty("inkCanvas",
+ // 通过反射访问主窗口的FloatingbarSelectionBG字段
+ var floatingbarSelectionBGField = _mainWindow.GetType().GetField("FloatingbarSelectionBG",
BindingFlags.NonPublic | BindingFlags.Instance);
- if (inkCanvasProperty != null)
+ if (floatingbarSelectionBGField != null)
{
- var inkCanvas = inkCanvasProperty.GetValue(_mainWindow);
- if (inkCanvas != null)
+ var floatingbarSelectionBG = floatingbarSelectionBGField.GetValue(_mainWindow);
+ if (floatingbarSelectionBG != null)
{
- // 通过反射访问EditingMode属性
- var editingModeProperty = inkCanvas.GetType().GetProperty("EditingMode");
- if (editingModeProperty != null)
+ // 检查高光是否可见
+ var visibilityProperty = floatingbarSelectionBG.GetType().GetProperty("Visibility");
+ if (visibilityProperty != null)
{
- var editingMode = editingModeProperty.GetValue(inkCanvas);
- // 检查是否为选择模式
- return editingMode != null && editingMode.ToString() == "Select";
+ var visibility = visibilityProperty.GetValue(floatingbarSelectionBG);
+ if (visibility != null && visibility.ToString() == "Hidden")
+ {
+ // 高光隐藏,说明没有选中任何工具,此时应该注销快捷键以释放系统快捷键
+ return true; // 返回true表示应该注销快捷键
+ }
+ }
+
+ // 通过反射访问Canvas.GetLeft方法来获取高光位置
+ var canvasType = Type.GetType("System.Windows.Controls.Canvas, PresentationFramework");
+ if (canvasType != null)
+ {
+ var getLeftMethod = canvasType.GetMethod("GetLeft", BindingFlags.Public | BindingFlags.Static);
+ if (getLeftMethod != null)
+ {
+ var leftPosition = getLeftMethod.Invoke(null, new object[] { floatingbarSelectionBG });
+ if (leftPosition != null)
+ {
+ var position = Convert.ToDouble(leftPosition);
+
+ // 根据高光位置判断当前选中的工具
+ // 位置计算基于SetFloatingBarHighlightPosition方法中的逻辑
+ bool isMouseMode = false;
+ string currentTool = "unknown";
+
+ // 简化判断:如果位置接近0,说明是鼠标模式
+ // 如果位置接近28,说明是批注模式
+ // 如果位置更大,说明是其他工具
+ if (position < 5) // 鼠标模式:marginOffset + (cursorWidth - actualHighlightWidth) / 2 ≈ 0
+ {
+ isMouseMode = true;
+ currentTool = "鼠标";
+ }
+ else if (position < 35) // 批注模式:marginOffset + cursorWidth + (penWidth - actualHighlightWidth) / 2 ≈ 28
+ {
+ isMouseMode = false;
+ currentTool = "批注";
+ }
+ else // 其他工具(橡皮擦、选择等)
+ {
+ isMouseMode = false;
+ currentTool = "其他工具";
+ }
+
+ return isMouseMode;
+ }
+ }
}
}
}
- return false;
+ // 如果无法获取高光状态,则回退到inkCanvas.EditingMode判断
+
+ // 通过反射访问主窗口的inkCanvas字段
+ var inkCanvasField = _mainWindow.GetType().GetField("inkCanvas",
+ BindingFlags.NonPublic | BindingFlags.Instance);
+
+ if (inkCanvasField != null)
+ {
+ var inkCanvas = inkCanvasField.GetValue(_mainWindow);
+ if (inkCanvas != null)
+ {
+ // 通过反射访问inkCanvas的EditingMode属性
+ var editingModeProperty = inkCanvas.GetType().GetProperty("EditingMode");
+ if (editingModeProperty != null)
+ {
+ var editingMode = editingModeProperty.GetValue(inkCanvas);
+ if (editingMode != null)
+ {
+ // 检查是否为批注模式
+ var isInkMode = editingMode.ToString().Contains("Ink");
+ var isSelectMode = editingMode.ToString().Contains("Select");
+
+ // 如果是批注模式或选择模式,则应该注册快捷键(返回false)
+ // 如果是橡皮擦模式或其他模式,则不应该注册快捷键(返回true)
+ var shouldNotRegisterHotkeys = !isInkMode && !isSelectMode;
+
+ return shouldNotRegisterHotkeys;
+ }
+ }
+ }
+ }
+
+ // 如果无法获取任何状态信息,则回退到原来的判断逻辑
+
+ // 通过反射访问主窗口的currentMode字段(作为最后的备用方案)
+ var currentModeField = _mainWindow.GetType().GetField("currentMode",
+ BindingFlags.NonPublic | BindingFlags.Instance);
+
+ if (currentModeField != null)
+ {
+ var currentMode = currentModeField.GetValue(_mainWindow);
+ if (currentMode != null)
+ {
+ var modeValue = currentMode.ToString();
+ // 注意:这里的逻辑需要修正
+ // currentMode == 0 表示屏幕模式(PPT放映),此时应该允许快捷键
+ // currentMode == 1 表示黑板/白板模式,此时也应该允许快捷键
+ var isSelectMode = false; // 修正:所有模式都应该允许快捷键
+ return isSelectMode;
+ }
+ }
+
+ return false; // 默认允许快捷键
}
catch (Exception ex)
{
- LogHelper.WriteLogToFile($"检查选择模式状态时出错: {ex.Message}", LogHelper.LogType.Warning);
- return false;
+ LogHelper.WriteLogToFile($"检查鼠标模式状态时出错: {ex.Message}", LogHelper.LogType.Warning);
+ return false; // 出错时默认允许快捷键
+ }
+ }
+
+ ///
+ /// 动态管理快捷键注册状态
+ /// 根据当前工具选择状态自动注册或注销快捷键
+ ///
+ public void UpdateHotkeyRegistrationState()
+ {
+ try
+ {
+ bool isMouseMode = IsInSelectMode();
+
+ if (isMouseMode)
+ {
+ // 在鼠标模式下,注销所有快捷键以释放系统快捷键
+ if (_hotkeysShouldBeRegistered)
+ {
+ UnregisterAllHotkeys();
+ _hotkeysShouldBeRegistered = false;
+ }
+ else
+ {
+ // 快捷键已经处于注销状态,无需重复注销
+ }
+ }
+ else
+ {
+ // 在批注/选择/其他工具模式下,重新注册所有快捷键
+ if (!_hotkeysShouldBeRegistered)
+ {
+ // 第一次切换到批注/选择/其他工具模式,启用快捷键注册
+ EnableHotkeyRegistration();
+ }
+ else if (_registeredHotkeys.Count == 0)
+ {
+ // 快捷键已启用但数量为0,重新注册
+ LoadHotkeysFromSettings();
+ }
+ else
+ {
+ // 当前已有快捷键注册,无需重新注册
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"更新快捷键注册状态时出错: {ex.Message}", LogHelper.LogType.Error);
}
}
#endregion
diff --git a/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs b/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs
index d16e083f..c3e14fed 100644
--- a/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs
+++ b/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs
@@ -706,6 +706,26 @@ namespace Ink_Canvas
SwitchToDefaultPen(null, null);
CheckColorTheme(true);
+
+ // 更新快捷键注册状态
+ try
+ {
+ var hotkeyManagerField = this.GetType().GetField("_globalHotkeyManager",
+ System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
+ if (hotkeyManagerField != null)
+ {
+ var hotkeyManager = hotkeyManagerField.GetValue(this);
+ if (hotkeyManager != null)
+ {
+ var updateMethod = hotkeyManager.GetType().GetMethod("UpdateHotkeyRegistrationState");
+ updateMethod?.Invoke(hotkeyManager, null);
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"更新快捷键状态时出错: {ex.Message}", LogHelper.LogType.Warning);
+ }
}
#endregion
@@ -788,6 +808,26 @@ namespace Ink_Canvas
BtnSelect_Click(null, null);
HideSubPanels("select");
+
+ // 更新快捷键注册状态
+ try
+ {
+ var hotkeyManagerField = this.GetType().GetField("_globalHotkeyManager",
+ System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
+ if (hotkeyManagerField != null)
+ {
+ var hotkeyManager = hotkeyManagerField.GetValue(this);
+ if (hotkeyManager != null)
+ {
+ var updateMethod = hotkeyManager.GetType().GetMethod("UpdateHotkeyRegistrationState");
+ updateMethod?.Invoke(hotkeyManager, null);
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"更新快捷键状态时出错: {ex.Message}", LogHelper.LogType.Warning);
+ }
}
#endregion
@@ -1615,6 +1655,26 @@ namespace Ink_Canvas
LogHelper.WriteLogToFile($"退出白板模式,恢复备份墨迹。当前模式:{(BtnPPTSlideShowEnd.Visibility == Visibility.Visible ? "PPT放映" : "桌面")}", LogHelper.LogType.Trace);
}
+ // 更新快捷键注册状态
+ try
+ {
+ var hotkeyManagerField = this.GetType().GetField("_globalHotkeyManager",
+ System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
+ if (hotkeyManagerField != null)
+ {
+ var hotkeyManager = hotkeyManagerField.GetValue(this);
+ if (hotkeyManager != null)
+ {
+ var updateMethod = hotkeyManager.GetType().GetMethod("UpdateHotkeyRegistrationState");
+ updateMethod?.Invoke(hotkeyManager, null);
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"更新快捷键状态时出错: {ex.Message}", LogHelper.LogType.Warning);
+ }
+
if (BtnSwitchTheme.Content.ToString() == "浅色")
BtnSwitch.Content = "黑板";
else
@@ -1730,6 +1790,26 @@ namespace Ink_Canvas
}
}
+ // 更新快捷键注册状态
+ try
+ {
+ var hotkeyManagerField = this.GetType().GetField("_globalHotkeyManager",
+ System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
+ if (hotkeyManagerField != null)
+ {
+ var hotkeyManager = hotkeyManagerField.GetValue(this);
+ if (hotkeyManager != null)
+ {
+ var updateMethod = hotkeyManager.GetType().GetMethod("UpdateHotkeyRegistrationState");
+ updateMethod?.Invoke(hotkeyManager, null);
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ // 更新快捷键状态时出错
+ }
+
// 修复:从线擦切换到批注时,保持之前的笔类型状态
// 如果之前是荧光笔模式,则保持荧光笔状态;否则重置为默认笔模式
forceEraser = false;
@@ -1910,6 +1990,26 @@ namespace Ink_Canvas
AnimationsHelper.HideWithSlideAndFade(BoardEraserSizePanel);
}
}
+
+ // 更新快捷键注册状态
+ try
+ {
+ var hotkeyManagerField = this.GetType().GetField("_globalHotkeyManager",
+ System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
+ if (hotkeyManagerField != null)
+ {
+ var hotkeyManager = hotkeyManagerField.GetValue(this);
+ if (hotkeyManager != null)
+ {
+ var updateMethod = hotkeyManager.GetType().GetMethod("UpdateHotkeyRegistrationState");
+ updateMethod?.Invoke(hotkeyManager, null);
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"更新快捷键状态时出错: {ex.Message}", LogHelper.LogType.Warning);
+ }
}
private void BoardEraserIcon_Click(object sender, RoutedEventArgs e)
From d1eed233999c9750821593cd616a30ab71204d93 Mon Sep 17 00:00:00 2001
From: CJKmkp <2564608840@qq.com>
Date: Sun, 24 Aug 2025 09:09:48 +0800
Subject: [PATCH 37/45] =?UTF-8?q?improve:=E5=BF=AB=E6=8D=B7=E9=94=AE?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Ink Canvas/Helpers/GlobalHotkeyManager.cs | 80 ++---
Ink Canvas/MainWindow.xaml.cs | 16 +-
.../Windows/HotkeySettingsWindow.xaml.cs | 277 ++++++++++++++----
3 files changed, 257 insertions(+), 116 deletions(-)
diff --git a/Ink Canvas/Helpers/GlobalHotkeyManager.cs b/Ink Canvas/Helpers/GlobalHotkeyManager.cs
index 82cb01c9..56d939e8 100644
--- a/Ink Canvas/Helpers/GlobalHotkeyManager.cs
+++ b/Ink Canvas/Helpers/GlobalHotkeyManager.cs
@@ -17,11 +17,10 @@ namespace Ink_Canvas.Helpers
private readonly Dictionary _registeredHotkeys;
private readonly MainWindow _mainWindow;
private bool _isDisposed = false;
- private bool _hotkeysShouldBeRegistered = true; // 跟踪快捷键是否应该被注册
+ private bool _hotkeysShouldBeRegistered = false; // 启动时不注册热键,等待需要时再注册
// 配置文件路径
private static readonly string HotkeyConfigFile = Path.Combine(App.RootPath, "HotkeyConfig.json");
- private static readonly string HotkeyConfigBackupFile = Path.Combine(App.RootPath, "HotkeyConfig.json.bak");
#endregion
#region Constructor
@@ -212,7 +211,7 @@ namespace Ink_Canvas.Helpers
}
///
- /// 从设置加载快捷键配置
+ /// 从设置加载快捷键
///
public void LoadHotkeysFromSettings()
{
@@ -232,20 +231,28 @@ namespace Ink_Canvas.Helpers
{
// 成功从配置文件加载快捷键设置
_hotkeysShouldBeRegistered = true;
+ LogHelper.WriteLogToFile("成功从配置文件加载快捷键设置", LogHelper.LogType.Info);
}
else
{
- // 如果配置文件不存在或加载失败,使用默认快捷键
- RegisterDefaultHotkeys();
- _hotkeysShouldBeRegistered = true;
+ // 如果配置文件不存在,才使用默认快捷键
+ if (!File.Exists(HotkeyConfigFile))
+ {
+ LogHelper.WriteLogToFile("配置文件不存在,注册默认快捷键", LogHelper.LogType.Info);
+ RegisterDefaultHotkeys();
+ _hotkeysShouldBeRegistered = true;
+ }
+ else
+ {
+ LogHelper.WriteLogToFile("配置文件存在但加载失败,保持当前状态", LogHelper.LogType.Warning);
+ }
}
}
- catch (Exception ex)
- {
- // 出错时使用默认快捷键
- RegisterDefaultHotkeys();
- _hotkeysShouldBeRegistered = true;
- }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"从设置加载快捷键时出错: {ex.Message}", LogHelper.LogType.Error);
+ // 出错时不自动使用默认快捷键,保持当前状态
+ }
}
///
@@ -283,18 +290,14 @@ namespace Ink_Canvas.Helpers
if (!_hotkeysShouldBeRegistered)
{
_hotkeysShouldBeRegistered = true;
+ LogHelper.WriteLogToFile("启用快捷键注册功能", LogHelper.LogType.Info);
- // 如果当前不在鼠标模式下,立即注册快捷键
- var currentIsMouseMode = IsInSelectMode();
-
- if (!currentIsMouseMode)
- {
- LoadHotkeysFromSettings();
- }
+ // 立即加载快捷键设置
+ LoadHotkeysFromSettings();
}
else
{
- // 快捷键注册功能已经启用
+ LogHelper.WriteLogToFile("快捷键注册功能已经启用", LogHelper.LogType.Info);
}
}
catch (Exception ex)
@@ -445,29 +448,6 @@ namespace Ink_Canvas.Helpers
catch (Exception ex)
{
LogHelper.WriteLogToFile($"从配置文件加载快捷键时出错: {ex.Message}", LogHelper.LogType.Error);
-
- // 尝试从备份文件加载
- if (File.Exists(HotkeyConfigBackupFile))
- {
- LogHelper.WriteLogToFile("尝试从备份文件加载快捷键配置", LogHelper.LogType.Warning);
- try
- {
- string backupContent = File.ReadAllText(HotkeyConfigBackupFile, System.Text.Encoding.UTF8);
- var backupConfig = JsonConvert.DeserializeObject(backupContent);
- if (backupConfig?.Hotkeys != null && backupConfig.Hotkeys.Count > 0)
- {
- // 恢复备份文件
- File.Copy(HotkeyConfigBackupFile, HotkeyConfigFile, true);
- LogHelper.WriteLogToFile("已从备份文件恢复快捷键配置", LogHelper.LogType.Event);
- return LoadHotkeysFromConfigFile();
- }
- }
- catch (Exception backupEx)
- {
- LogHelper.WriteLogToFile($"从备份文件加载快捷键配置时出错: {backupEx.Message}", LogHelper.LogType.Error);
- }
- }
-
return false;
}
}
@@ -514,18 +494,8 @@ namespace Ink_Canvas.Helpers
string jsonContent = JsonConvert.SerializeObject(config, settings);
- // 先写入临时文件,然后替换原文件(原子操作)
- string tempFile = HotkeyConfigFile + ".temp";
- File.WriteAllText(tempFile, jsonContent, System.Text.Encoding.UTF8);
-
- // 如果原文件存在,先备份
- if (File.Exists(HotkeyConfigFile))
- {
- File.Copy(HotkeyConfigFile, HotkeyConfigBackupFile, true);
- }
-
- // 替换原文件
- File.Move(tempFile, HotkeyConfigFile);
+ // 直接写入原文件,覆盖原有内容
+ File.WriteAllText(HotkeyConfigFile, jsonContent, System.Text.Encoding.UTF8);
LogHelper.WriteLogToFile($"快捷键配置已保存到: {HotkeyConfigFile}", LogHelper.LogType.Event);
return true;
diff --git a/Ink Canvas/MainWindow.xaml.cs b/Ink Canvas/MainWindow.xaml.cs
index 93f58fb1..a744cc09 100644
--- a/Ink Canvas/MainWindow.xaml.cs
+++ b/Ink Canvas/MainWindow.xaml.cs
@@ -2016,8 +2016,8 @@ namespace Ink_Canvas
try
{
_globalHotkeyManager = new GlobalHotkeyManager(this);
- _globalHotkeyManager.LoadHotkeysFromSettings();
- LogHelper.WriteLogToFile("全局快捷键管理器已初始化", LogHelper.LogType.Event);
+ // 不在这里加载快捷键,等待需要时再加载
+ LogHelper.WriteLogToFile("全局快捷键管理器已初始化(未加载快捷键)", LogHelper.LogType.Event);
}
catch (Exception ex)
{
@@ -2064,6 +2064,12 @@ namespace Ink_Canvas
{
ToggleSwitchInkFadeInPanel.IsOn = Settings.Canvas.EnableInkFade;
}
+
+ // 同步普通画笔面板中的开关状态
+ if (ToggleSwitchInkFadeInPanel2 != null)
+ {
+ ToggleSwitchInkFadeInPanel2.IsOn = Settings.Canvas.EnableInkFade;
+ }
LogHelper.WriteLogToFile($"墨迹渐隐功能已{(Settings.Canvas.EnableInkFade ? "启用" : "禁用")}", LogHelper.LogType.Event);
}
@@ -2107,6 +2113,12 @@ namespace Ink_Canvas
{
ToggleSwitchEnableInkFade.IsOn = Settings.Canvas.EnableInkFade;
}
+
+ // 同步普通画笔面板中的开关状态
+ if (ToggleSwitchInkFadeInPanel2 != null)
+ {
+ ToggleSwitchInkFadeInPanel2.IsOn = Settings.Canvas.EnableInkFade;
+ }
LogHelper.WriteLogToFile($"批注子面板中墨迹渐隐功能已{(Settings.Canvas.EnableInkFade ? "启用" : "禁用")}", LogHelper.LogType.Event);
}
diff --git a/Ink Canvas/Windows/HotkeySettingsWindow.xaml.cs b/Ink Canvas/Windows/HotkeySettingsWindow.xaml.cs
index 1d3c30dc..d723c0f6 100644
--- a/Ink Canvas/Windows/HotkeySettingsWindow.xaml.cs
+++ b/Ink Canvas/Windows/HotkeySettingsWindow.xaml.cs
@@ -28,8 +28,22 @@ namespace Ink_Canvas.Windows
// 隐藏主窗口的设置页面
HideMainWindowSettings();
InitializeHotkeyItems();
- LoadCurrentHotkeys();
- SetupEventHandlers();
+
+ // 延迟加载快捷键,确保快捷键管理器已完全初始化
+ this.Loaded += (s, e) =>
+ {
+ try
+ {
+ // 不自动启用快捷键注册功能,让用户手动决定
+ // 只加载当前已注册的快捷键
+ LoadCurrentHotkeys();
+ SetupEventHandlers();
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"快捷键设置窗口初始化时出错: {ex.Message}", LogHelper.LogType.Error);
+ }
+ };
// 注册窗口关闭事件
this.Closed += HotkeySettingsWindow_Closed;
@@ -39,60 +53,71 @@ namespace Ink_Canvas.Windows
#region Private Methods
private void InitializeHotkeyItems()
{
- // 初始化快捷键项并设置HotkeyName
- _hotkeyItems["Undo"] = UndoHotkey;
- UndoHotkey.HotkeyName = "Undo";
-
- _hotkeyItems["Redo"] = RedoHotkey;
- RedoHotkey.HotkeyName = "Redo";
-
- _hotkeyItems["Clear"] = ClearHotkey;
- ClearHotkey.HotkeyName = "Clear";
-
- _hotkeyItems["Paste"] = PasteHotkey;
- PasteHotkey.HotkeyName = "Paste";
-
- _hotkeyItems["SelectTool"] = SelectToolHotkey;
- SelectToolHotkey.HotkeyName = "SelectTool";
-
- _hotkeyItems["DrawTool"] = DrawToolHotkey;
- DrawToolHotkey.HotkeyName = "DrawTool";
-
- _hotkeyItems["EraserTool"] = EraserToolHotkey;
- EraserToolHotkey.HotkeyName = "EraserTool";
-
- _hotkeyItems["BlackboardTool"] = BlackboardToolHotkey;
- BlackboardToolHotkey.HotkeyName = "BlackboardTool";
-
- _hotkeyItems["QuitDrawTool"] = QuitDrawToolHotkey;
- QuitDrawToolHotkey.HotkeyName = "QuitDrawTool";
-
- _hotkeyItems["Pen1"] = Pen1Hotkey;
- Pen1Hotkey.HotkeyName = "Pen1";
-
- _hotkeyItems["Pen2"] = Pen2Hotkey;
- Pen2Hotkey.HotkeyName = "Pen2";
-
- _hotkeyItems["Pen3"] = Pen3Hotkey;
- Pen3Hotkey.HotkeyName = "Pen3";
-
- _hotkeyItems["Pen4"] = Pen4Hotkey;
- Pen4Hotkey.HotkeyName = "Pen4";
-
- _hotkeyItems["Pen5"] = Pen5Hotkey;
- Pen5Hotkey.HotkeyName = "Pen5";
-
- _hotkeyItems["DrawLine"] = DrawLineHotkey;
- DrawLineHotkey.HotkeyName = "DrawLine";
-
- _hotkeyItems["Screenshot"] = ScreenshotHotkey;
- ScreenshotHotkey.HotkeyName = "Screenshot";
-
- _hotkeyItems["Hide"] = HideHotkey;
- HideHotkey.HotkeyName = "Hide";
-
- _hotkeyItems["Exit"] = ExitHotkey;
- ExitHotkey.HotkeyName = "Exit";
+ try
+ {
+ LogHelper.WriteLogToFile("开始初始化快捷键项", LogHelper.LogType.Info);
+
+ // 初始化快捷键项并设置HotkeyName
+ _hotkeyItems["Undo"] = UndoHotkey;
+ UndoHotkey.HotkeyName = "Undo";
+
+ _hotkeyItems["Redo"] = RedoHotkey;
+ RedoHotkey.HotkeyName = "Redo";
+
+ _hotkeyItems["Clear"] = ClearHotkey;
+ ClearHotkey.HotkeyName = "Clear";
+
+ _hotkeyItems["Paste"] = PasteHotkey;
+ PasteHotkey.HotkeyName = "Paste";
+
+ _hotkeyItems["SelectTool"] = SelectToolHotkey;
+ SelectToolHotkey.HotkeyName = "SelectTool";
+
+ _hotkeyItems["DrawTool"] = DrawToolHotkey;
+ DrawToolHotkey.HotkeyName = "DrawTool";
+
+ _hotkeyItems["EraserTool"] = EraserToolHotkey;
+ EraserToolHotkey.HotkeyName = "EraserTool";
+
+ _hotkeyItems["BlackboardTool"] = BlackboardToolHotkey;
+ BlackboardToolHotkey.HotkeyName = "BlackboardTool";
+
+ _hotkeyItems["QuitDrawTool"] = QuitDrawToolHotkey;
+ QuitDrawToolHotkey.HotkeyName = "QuitDrawTool";
+
+ _hotkeyItems["Pen1"] = Pen1Hotkey;
+ Pen1Hotkey.HotkeyName = "Pen1";
+
+ _hotkeyItems["Pen2"] = Pen2Hotkey;
+ Pen2Hotkey.HotkeyName = "Pen2";
+
+ _hotkeyItems["Pen3"] = Pen3Hotkey;
+ Pen3Hotkey.HotkeyName = "Pen3";
+
+ _hotkeyItems["Pen4"] = Pen4Hotkey;
+ Pen4Hotkey.HotkeyName = "Pen4";
+
+ _hotkeyItems["Pen5"] = Pen5Hotkey;
+ Pen5Hotkey.HotkeyName = "Pen5";
+
+ _hotkeyItems["DrawLine"] = DrawLineHotkey;
+ DrawLineHotkey.HotkeyName = "DrawLine";
+
+ _hotkeyItems["Screenshot"] = ScreenshotHotkey;
+ ScreenshotHotkey.HotkeyName = "Screenshot";
+
+ _hotkeyItems["Hide"] = HideHotkey;
+ HideHotkey.HotkeyName = "Hide";
+
+ _hotkeyItems["Exit"] = ExitHotkey;
+ ExitHotkey.HotkeyName = "Exit";
+
+ LogHelper.WriteLogToFile($"成功初始化 {_hotkeyItems.Count} 个快捷键项", LogHelper.LogType.Info);
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"初始化快捷键项时出错: {ex.Message}", LogHelper.LogType.Error);
+ }
}
private void LoadCurrentHotkeys()
@@ -100,13 +125,21 @@ namespace Ink_Canvas.Windows
try
{
var registeredHotkeys = _hotkeyManager.GetRegisteredHotkeys();
+ LogHelper.WriteLogToFile($"当前已注册快捷键数量: {registeredHotkeys.Count}", LogHelper.LogType.Info);
+
+ // 显示已注册的快捷键
foreach (var hotkey in registeredHotkeys)
{
if (_hotkeyItems.TryGetValue(hotkey.Name, out var hotkeyItem))
{
hotkeyItem.SetCurrentHotkey(hotkey.Key, hotkey.Modifiers);
+ LogHelper.WriteLogToFile($"设置快捷键项: {hotkey.Name} -> {hotkey.Modifiers}+{hotkey.Key}", LogHelper.LogType.Info);
}
}
+
+ // 对于没有快捷键的项目,不设置任何值,保持为空状态
+ // 这样用户就能清楚地知道哪些快捷键还没有设置
+ LogHelper.WriteLogToFile("未注册的快捷键项保持为空状态", LogHelper.LogType.Info);
}
catch (Exception ex)
{
@@ -114,6 +147,78 @@ namespace Ink_Canvas.Windows
}
}
+ ///
+ /// 为快捷键项设置默认值
+ ///
+ private void SetDefaultHotkeyForItem(HotkeyItem hotkeyItem)
+ {
+ try
+ {
+ // 根据HotkeyName设置默认快捷键
+ switch (hotkeyItem.HotkeyName)
+ {
+ case "Undo":
+ hotkeyItem.SetCurrentHotkey(Key.Z, ModifierKeys.Control);
+ break;
+ case "Redo":
+ hotkeyItem.SetCurrentHotkey(Key.Y, ModifierKeys.Control);
+ break;
+ case "Clear":
+ hotkeyItem.SetCurrentHotkey(Key.E, ModifierKeys.Control);
+ break;
+ case "Paste":
+ hotkeyItem.SetCurrentHotkey(Key.V, ModifierKeys.Control);
+ break;
+ case "SelectTool":
+ hotkeyItem.SetCurrentHotkey(Key.S, ModifierKeys.Alt);
+ break;
+ case "DrawTool":
+ hotkeyItem.SetCurrentHotkey(Key.D, ModifierKeys.Alt);
+ break;
+ case "EraserTool":
+ hotkeyItem.SetCurrentHotkey(Key.E, ModifierKeys.Alt);
+ break;
+ case "BlackboardTool":
+ hotkeyItem.SetCurrentHotkey(Key.B, ModifierKeys.Alt);
+ break;
+ case "QuitDrawTool":
+ hotkeyItem.SetCurrentHotkey(Key.Q, ModifierKeys.Alt);
+ break;
+ case "Pen1":
+ hotkeyItem.SetCurrentHotkey(Key.D1, ModifierKeys.Alt);
+ break;
+ case "Pen2":
+ hotkeyItem.SetCurrentHotkey(Key.D2, ModifierKeys.Alt);
+ break;
+ case "Pen3":
+ hotkeyItem.SetCurrentHotkey(Key.D3, ModifierKeys.Alt);
+ break;
+ case "Pen4":
+ hotkeyItem.SetCurrentHotkey(Key.D4, ModifierKeys.Alt);
+ break;
+ case "Pen5":
+ hotkeyItem.SetCurrentHotkey(Key.D5, ModifierKeys.Alt);
+ break;
+ case "DrawLine":
+ hotkeyItem.SetCurrentHotkey(Key.L, ModifierKeys.Alt);
+ break;
+ case "Screenshot":
+ hotkeyItem.SetCurrentHotkey(Key.C, ModifierKeys.Alt);
+ break;
+ case "Hide":
+ hotkeyItem.SetCurrentHotkey(Key.V, ModifierKeys.Alt);
+ break;
+ case "Exit":
+ hotkeyItem.SetCurrentHotkey(Key.Escape, ModifierKeys.None);
+ break;
+ }
+ }
+ catch (Exception ex)
+ {
+ // 设置默认快捷键时出错,忽略
+ }
+ }
+
private void SetupEventHandlers()
{
// 为每个快捷键项设置事件处理器
@@ -127,6 +232,8 @@ namespace Ink_Canvas.Windows
{
try
{
+ LogHelper.WriteLogToFile($"收到快捷键变更事件: {e.HotkeyName} -> {e.Modifiers}+{e.Key}", LogHelper.LogType.Info);
+
// 检查快捷键冲突
if (IsHotkeyConflict(e.Key, e.Modifiers, e.HotkeyName))
{
@@ -146,6 +253,7 @@ namespace Ink_Canvas.Windows
private bool IsHotkeyConflict(Key key, ModifierKeys modifiers, string excludeHotkeyName)
{
+ // 检查是否与已注册的快捷键冲突
var registeredHotkeys = _hotkeyManager.GetRegisteredHotkeys();
foreach (var hotkey in registeredHotkeys)
{
@@ -156,6 +264,29 @@ namespace Ink_Canvas.Windows
return true;
}
}
+
+ // 检查是否与默认快捷键冲突(如果当前快捷键项还没有注册)
+ if (excludeHotkeyName != null && _hotkeyItems.TryGetValue(excludeHotkeyName, out var currentItem))
+ {
+ var currentHotkey = currentItem.GetCurrentHotkey();
+ if (currentHotkey.key == Key.None)
+ {
+ // 如果当前项还没有快捷键,检查是否与其他默认快捷键冲突
+ foreach (var kvp in _hotkeyItems)
+ {
+ if (kvp.Key != excludeHotkeyName)
+ {
+ var item = kvp.Value;
+ var itemHotkey = item.GetCurrentHotkey();
+ if (itemHotkey.key == key && itemHotkey.modifiers == modifiers)
+ {
+ return true;
+ }
+ }
+ }
+ }
+ }
+
return false;
}
@@ -163,20 +294,42 @@ namespace Ink_Canvas.Windows
{
try
{
+ LogHelper.WriteLogToFile($"开始更新快捷键: {hotkeyName} -> {modifiers}+{key}", LogHelper.LogType.Info);
+
+ // 先注销原有的快捷键(如果存在)
+ _hotkeyManager.UnregisterHotkey(hotkeyName);
+ LogHelper.WriteLogToFile($"已注销原有快捷键: {hotkeyName}", LogHelper.LogType.Info);
+
// 根据快捷键名称获取对应的动作
var action = GetActionForHotkey(hotkeyName);
if (action != null)
{
- // 使用快捷键管理器的UpdateHotkey方法,这会自动保存配置
- if (_hotkeyManager.UpdateHotkey(hotkeyName, key, modifiers))
+ LogHelper.WriteLogToFile($"找到快捷键动作: {hotkeyName}", LogHelper.LogType.Info);
+
+ // 直接注册新的快捷键
+ if (_hotkeyManager.RegisterHotkey(hotkeyName, key, modifiers, action))
{
- LogHelper.WriteLogToFile($"快捷键 {hotkeyName} 已更新为 {modifiers}+{key} 并自动保存", LogHelper.LogType.Event);
+ LogHelper.WriteLogToFile($"成功注册新快捷键: {hotkeyName} -> {modifiers}+{key}", LogHelper.LogType.Info);
+
+ // 立即保存到配置文件
+ _hotkeyManager.SaveHotkeysToSettings();
+ LogHelper.WriteLogToFile($"已保存快捷键配置", LogHelper.LogType.Info);
+
+ // 更新UI显示
+ LoadCurrentHotkeys();
+ LogHelper.WriteLogToFile($"已更新UI显示", LogHelper.LogType.Info);
+
+ LogHelper.WriteLogToFile($"快捷键 {hotkeyName} 已更新为 {modifiers}+{key} 并保存", LogHelper.LogType.Event);
}
else
{
LogHelper.WriteLogToFile($"更新快捷键 {hotkeyName} 失败", LogHelper.LogType.Error);
}
}
+ else
+ {
+ LogHelper.WriteLogToFile($"未找到快捷键 {hotkeyName} 对应的动作", LogHelper.LogType.Warning);
+ }
}
catch (Exception ex)
{
@@ -351,9 +504,15 @@ namespace Ink_Canvas.Windows
"确认重置", MessageBoxButton.YesNo, MessageBoxImage.Question);
if (result == MessageBoxResult.Yes)
{
+ // 先注销所有现有快捷键
+ _hotkeyManager.UnregisterAllHotkeys();
+
// 重置为默认快捷键
_hotkeyManager.RegisterDefaultHotkeys();
+ // 立即保存到配置文件
+ _hotkeyManager.SaveHotkeysToSettings();
+
// 更新UI显示
LoadCurrentHotkeys();
From 7710b7725567f72b4ac9683a31b4669f8d211385 Mon Sep 17 00:00:00 2001
From: CJKmkp <2564608840@qq.com>
Date: Sun, 24 Aug 2025 09:17:58 +0800
Subject: [PATCH 38/45] =?UTF-8?q?improve:=E5=BF=AB=E6=8D=B7=E9=94=AE?=
=?UTF-8?q?=E5=92=8C=E5=A2=A8=E8=BF=B9=E6=B8=90=E9=9A=90?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Ink Canvas/Helpers/GlobalHotkeyManager.cs | 55 ++++-
Ink Canvas/MainWindow.xaml | 222 +++++++++---------
Ink Canvas/MainWindow_cs/MW_SettingsToLoad.cs | 6 +
.../Windows/HotkeySettingsWindow.xaml.cs | 31 ++-
4 files changed, 198 insertions(+), 116 deletions(-)
diff --git a/Ink Canvas/Helpers/GlobalHotkeyManager.cs b/Ink Canvas/Helpers/GlobalHotkeyManager.cs
index 56d939e8..66d7cba2 100644
--- a/Ink Canvas/Helpers/GlobalHotkeyManager.cs
+++ b/Ink Canvas/Helpers/GlobalHotkeyManager.cs
@@ -165,6 +165,59 @@ namespace Ink_Canvas.Helpers
return new List(_registeredHotkeys.Values);
}
+ ///
+ /// 获取配置文件中的快捷键信息(不注册,仅用于显示)
+ ///
+ /// 配置文件中的快捷键列表
+ public List GetHotkeysFromConfigFile()
+ {
+ try
+ {
+ if (!File.Exists(HotkeyConfigFile))
+ {
+ LogHelper.WriteLogToFile("快捷键配置文件不存在", LogHelper.LogType.Info);
+ return new List();
+ }
+
+ // 读取配置文件内容
+ string jsonContent = File.ReadAllText(HotkeyConfigFile, System.Text.Encoding.UTF8);
+ if (string.IsNullOrEmpty(jsonContent))
+ {
+ LogHelper.WriteLogToFile("快捷键配置文件为空", LogHelper.LogType.Warning);
+ return new List();
+ }
+
+ // 反序列化配置
+ var config = JsonConvert.DeserializeObject(jsonContent);
+ if (config?.Hotkeys == null || config.Hotkeys.Count == 0)
+ {
+ LogHelper.WriteLogToFile("快捷键配置为空或格式错误", LogHelper.LogType.Warning);
+ return new List();
+ }
+
+ // 转换为HotkeyInfo列表(不注册,仅用于显示)
+ var hotkeyList = new List();
+ foreach (var hotkeyConfig in config.Hotkeys)
+ {
+ hotkeyList.Add(new HotkeyInfo
+ {
+ Name = hotkeyConfig.Name,
+ Key = hotkeyConfig.Key,
+ Modifiers = hotkeyConfig.Modifiers,
+ Action = null // 不设置动作,仅用于显示
+ });
+ }
+
+ LogHelper.WriteLogToFile($"从配置文件读取到 {hotkeyList.Count} 个快捷键信息", LogHelper.LogType.Info);
+ return hotkeyList;
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"从配置文件读取快捷键信息时出错: {ex.Message}", LogHelper.LogType.Error);
+ return new List();
+ }
+ }
+
///
/// 注册默认快捷键集合
///
@@ -211,7 +264,7 @@ namespace Ink_Canvas.Helpers
}
///
- /// 从设置加载快捷键
+ /// 从配置文件加载快捷键
///
public void LoadHotkeysFromSettings()
{
diff --git a/Ink Canvas/MainWindow.xaml b/Ink Canvas/MainWindow.xaml
index f9f94034..37247924 100644
--- a/Ink Canvas/MainWindow.xaml
+++ b/Ink Canvas/MainWindow.xaml
@@ -4061,7 +4061,7 @@
-
@@ -4176,57 +4176,69 @@
Margin="12,8,12,0" HorizontalAlignment="Center"
VerticalAlignment="Center" Stretch="Fill">
-
+
+
+
+
+
+
+
+
-
-
-
+
+
-
-
-
-
+ Width="80" Margin="10,0,0,0"
+ Toggled="ToggleSwitchEnableNibMode_Toggled"
+ IsOn="True" />
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
@@ -7193,53 +7205,63 @@
Margin="12,8,12,0" HorizontalAlignment="Center"
VerticalAlignment="Center" Stretch="Fill">
-
-
-
+
+
+
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
@@ -7994,17 +8016,7 @@
-
-
-
-
-
-
+
{hotkey.Modifiers}+{hotkey.Key}", LogHelper.LogType.Info);
+ LogHelper.WriteLogToFile($"从配置文件设置快捷键项: {hotkey.Name} -> {hotkey.Modifiers}+{hotkey.Key}", LogHelper.LogType.Info);
}
}
- // 对于没有快捷键的项目,不设置任何值,保持为空状态
- // 这样用户就能清楚地知道哪些快捷键还没有设置
- LogHelper.WriteLogToFile("未注册的快捷键项保持为空状态", LogHelper.LogType.Info);
+ // 为没有快捷键的项目设置默认显示值(仅用于UI显示,不实际注册)
+ foreach (var kvp in _hotkeyItems)
+ {
+ var hotkeyItem = kvp.Value;
+ if (hotkeyItem.GetCurrentHotkey().key == Key.None)
+ {
+ // 根据DefaultKey和DefaultModifiers设置默认显示值
+ SetDefaultHotkeyForItem(hotkeyItem);
+ LogHelper.WriteLogToFile($"设置默认显示值: {hotkeyItem.HotkeyName}", LogHelper.LogType.Info);
+ }
+ }
}
catch (Exception ex)
{
From 2c70d243dfb019c221f9ba8f9d02557e52672d2f Mon Sep 17 00:00:00 2001
From: CJKmkp <2564608840@qq.com>
Date: Sun, 24 Aug 2025 09:33:27 +0800
Subject: [PATCH 39/45] =?UTF-8?q?improve:=E5=A2=A8=E8=BF=B9=E6=B8=90?=
=?UTF-8?q?=E9=9A=90=E5=BC=80=E5=85=B3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Ink Canvas/MainWindow.xaml | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/Ink Canvas/MainWindow.xaml b/Ink Canvas/MainWindow.xaml
index 37247924..9cc67eca 100644
--- a/Ink Canvas/MainWindow.xaml
+++ b/Ink Canvas/MainWindow.xaml
@@ -4201,7 +4201,7 @@
-
-
+ FontSize="12" VerticalAlignment="Center" />
+ FontSize="12" VerticalAlignment="Center" />
Date: Sun, 24 Aug 2025 09:46:52 +0800
Subject: [PATCH 40/45] =?UTF-8?q?fix:=E9=94=99=E8=AF=AF=E7=9A=84=E5=94=A4?=
=?UTF-8?q?=E8=B5=B7URL?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Ink Canvas/Windows/RandWindow.xaml.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Ink Canvas/Windows/RandWindow.xaml.cs b/Ink Canvas/Windows/RandWindow.xaml.cs
index 3e801682..4b4c5f5e 100644
--- a/Ink Canvas/Windows/RandWindow.xaml.cs
+++ b/Ink Canvas/Windows/RandWindow.xaml.cs
@@ -319,7 +319,7 @@ namespace Ink_Canvas
protocol = "secrandom://pumping?action=start";
break;
case 2: // NamePicker点名
- protocol = "namepicker://调起没有浮窗的NamePicker";
+ protocol = "namepicker://";
break;
default:
protocol = "classisland://plugins/IslandCaller/Simple/1";
From fd9b4b4ba6a5b3bc21742c114e186b7a2bfe482b Mon Sep 17 00:00:00 2001
From: CJKmkp <2564608840@qq.com>
Date: Sun, 24 Aug 2025 10:17:21 +0800
Subject: [PATCH 41/45] =?UTF-8?q?improve:=E5=A2=A8=E8=BF=B9=E6=B8=90?=
=?UTF-8?q?=E9=9A=90=E5=BC=80=E5=85=B3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Ink Canvas/MainWindow.xaml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/Ink Canvas/MainWindow.xaml b/Ink Canvas/MainWindow.xaml
index 9cc67eca..da24ff88 100644
--- a/Ink Canvas/MainWindow.xaml
+++ b/Ink Canvas/MainWindow.xaml
@@ -4075,7 +4075,7 @@
Background="#fafafa"
Opacity="1" BorderBrush="#2563eb"
BorderThickness="1" CornerRadius="8">
-
+
-
+
Date: Sun, 24 Aug 2025 10:39:24 +0800
Subject: [PATCH 42/45] =?UTF-8?q?improve:=E9=95=BF=E6=8C=89=E7=BF=BB?=
=?UTF-8?q?=E9=A1=B5?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Ink Canvas/MainWindow_cs/MW_PPT.cs | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/Ink Canvas/MainWindow_cs/MW_PPT.cs b/Ink Canvas/MainWindow_cs/MW_PPT.cs
index 4834a155..3efc6e72 100644
--- a/Ink Canvas/MainWindow_cs/MW_PPT.cs
+++ b/Ink Canvas/MainWindow_cs/MW_PPT.cs
@@ -86,8 +86,8 @@ namespace Ink_Canvas
private DispatcherTimer _longPressTimer;
private bool _isLongPressActive = false;
private bool _isLongPressNext = true; // true为下一页,false为上一页
- private const int LongPressDelay = 500; // 长按延迟时间(毫秒)
- private const int LongPressInterval = 200; // 长按翻页间隔(毫秒)
+ private const int LongPressDelay = 50; // 长按延迟时间(毫秒)
+ private const int LongPressInterval = 50; // 长按翻页间隔(毫秒)
#endregion
#region PPT Managers
From 22da4cc40882eac565f3c3d36f34fe7cc9d84029 Mon Sep 17 00:00:00 2001
From: CJKmkp <2564608840@qq.com>
Date: Sun, 24 Aug 2025 11:08:13 +0800
Subject: [PATCH 43/45] =?UTF-8?q?fix:=E6=97=A0=E7=84=A6=E7=82=B9=E6=97=A0?=
=?UTF-8?q?=E6=B3=95=E7=BF=BB=E9=A1=B5?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Ink Canvas/MainWindow.xaml.cs | 55 +++++++++++++++++++++++++-
Ink Canvas/MainWindow_cs/MW_Hotkeys.cs | 31 ++++++++++++---
2 files changed, 79 insertions(+), 7 deletions(-)
diff --git a/Ink Canvas/MainWindow.xaml.cs b/Ink Canvas/MainWindow.xaml.cs
index a744cc09..c4667900 100644
--- a/Ink Canvas/MainWindow.xaml.cs
+++ b/Ink Canvas/MainWindow.xaml.cs
@@ -9,6 +9,7 @@ using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
+using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Threading;
@@ -292,9 +293,15 @@ namespace Ink_Canvas
if (StackPanelPPTControls.Visibility == Visibility.Visible)
{
if (gest.ApplicationGesture == ApplicationGesture.Left)
- BtnPPTSlidesDown_Click(BtnPPTSlidesDown, null);
+ {
+ // 直接发送翻页请求到PPT放映软件
+ SendKeyToPPTSlideShow(false); // 下一页
+ }
if (gest.ApplicationGesture == ApplicationGesture.Right)
- BtnPPTSlidesUp_Click(BtnPPTSlidesUp, null);
+ {
+ // 直接发送翻页请求到PPT放映软件
+ SendKeyToPPTSlideShow(true); // 上一页
+ }
}
}
catch { }
@@ -1667,6 +1674,8 @@ namespace Ink_Canvas
private static extern bool BringWindowToTop(IntPtr hWnd);
[DllImport("user32.dll")]
private static extern bool SetForegroundWindow(IntPtr hWnd);
+ [DllImport("user32.dll")]
+ private static extern bool PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
private const int GWL_EXSTYLE = -20;
@@ -2128,5 +2137,47 @@ namespace Ink_Canvas
}
}
#endregion
+
+ #region PPT翻页直接传递
+ ///
+ /// 直接发送翻页请求到PPT放映软件,让PPT软件处理翻页
+ ///
+ /// 是否为上一页
+ private void SendKeyToPPTSlideShow(bool isPrevious)
+ {
+ try
+ {
+ // 查找PPT放映窗口并发送按键
+ var pptWindows = Process.GetProcessesByName("POWERPNT");
+ var wpsWindows = Process.GetProcessesByName("wpp");
+
+ foreach (var process in pptWindows.Concat(wpsWindows))
+ {
+ if (process.MainWindowHandle != IntPtr.Zero)
+ {
+ // 激活PPT窗口
+ SetForegroundWindow(process.MainWindowHandle);
+
+ // 发送翻页按键消息
+ int keyCode = isPrevious ? 0x21 : 0x22; // VK_PRIOR : VK_NEXT
+
+ // 发送按键按下和释放消息
+ PostMessage(process.MainWindowHandle, 0x0100, (IntPtr)keyCode, IntPtr.Zero); // WM_KEYDOWN
+ PostMessage(process.MainWindowHandle, 0x0101, (IntPtr)keyCode, IntPtr.Zero); // WM_KEYUP
+
+ break;
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ // 如果直接发送失败,回退到原来的方法
+ if (isPrevious)
+ BtnPPTSlidesUp_Click(BtnPPTSlidesUp, null);
+ else
+ BtnPPTSlidesDown_Click(BtnPPTSlidesDown, null);
+ }
+ }
+ #endregion
}
}
diff --git a/Ink Canvas/MainWindow_cs/MW_Hotkeys.cs b/Ink Canvas/MainWindow_cs/MW_Hotkeys.cs
index 79ef9e5f..edcbbbb1 100644
--- a/Ink Canvas/MainWindow_cs/MW_Hotkeys.cs
+++ b/Ink Canvas/MainWindow_cs/MW_Hotkeys.cs
@@ -1,5 +1,9 @@
using System.Windows;
using System.Windows.Input;
+using System.Diagnostics;
+using System;
+using System.Linq;
+using System.Runtime.InteropServices;
namespace Ink_Canvas
{
@@ -8,19 +12,36 @@ namespace Ink_Canvas
private void Window_MouseWheel(object sender, MouseWheelEventArgs e)
{
if (StackPanelPPTControls.Visibility != Visibility.Visible || currentMode != 0) return;
+
+ // 直接发送翻页请求到PPT放映软件,不通过软件处理
if (e.Delta >= 120)
- BtnPPTSlidesUp_Click(BtnPPTSlidesUp, null);
- else if (e.Delta <= -120) BtnPPTSlidesDown_Click(BtnPPTSlidesDown, null);
+ {
+ // 上一页 - 发送PageUp键到PPT放映窗口
+ SendKeyToPPTSlideShow(true);
+ }
+ else if (e.Delta <= -120)
+ {
+ // 下一页 - 发送PageDown键到PPT放映窗口
+ SendKeyToPPTSlideShow(false);
+ }
}
private void Main_Grid_PreviewKeyDown(object sender, KeyEventArgs e)
{
if (StackPanelPPTControls.Visibility != Visibility.Visible || currentMode != 0) return;
+ // 直接发送翻页请求到PPT放映软件,不通过软件处理
if (e.Key == Key.Down || e.Key == Key.PageDown || e.Key == Key.Right || e.Key == Key.N ||
- e.Key == Key.Space) BtnPPTSlidesDown_Click(BtnPPTSlidesDown, null);
- if (e.Key == Key.Up || e.Key == Key.PageUp || e.Key == Key.Left || e.Key == Key.P)
- BtnPPTSlidesUp_Click(BtnPPTSlidesUp, null);
+ e.Key == Key.Space)
+ {
+ e.Handled = true; // 阻止事件继续传播
+ SendKeyToPPTSlideShow(false); // 下一页
+ }
+ else if (e.Key == Key.Up || e.Key == Key.PageUp || e.Key == Key.Left || e.Key == Key.P)
+ {
+ e.Handled = true; // 阻止事件继续传播
+ SendKeyToPPTSlideShow(true); // 上一页
+ }
}
private void Window_KeyDown(object sender, KeyEventArgs e)
From d7f6433b537789cc2b00820c3617972aa07f317f Mon Sep 17 00:00:00 2001
From: CJKmkp <2564608840@qq.com>
Date: Sun, 24 Aug 2025 11:09:41 +0800
Subject: [PATCH 44/45] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E7=89=88=E6=9C=AC?=
=?UTF-8?q?=E5=8F=B7?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Ink Canvas/AssemblyInfo.cs | 4 ++--
Ink Canvas/Properties/AssemblyInfo.cs | 4 ++--
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/Ink Canvas/AssemblyInfo.cs b/Ink Canvas/AssemblyInfo.cs
index d97781ce..00caa8a6 100644
--- a/Ink Canvas/AssemblyInfo.cs
+++ b/Ink Canvas/AssemblyInfo.cs
@@ -49,5 +49,5 @@ using System.Windows;
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("1.7.7.6")]
-[assembly: AssemblyFileVersion("1.7.7.6")]
+[assembly: AssemblyVersion("1.7.7.7")]
+[assembly: AssemblyFileVersion("1.7.7.7")]
diff --git a/Ink Canvas/Properties/AssemblyInfo.cs b/Ink Canvas/Properties/AssemblyInfo.cs
index 5c0248e6..f92a4964 100644
--- a/Ink Canvas/Properties/AssemblyInfo.cs
+++ b/Ink Canvas/Properties/AssemblyInfo.cs
@@ -49,5 +49,5 @@ using System.Windows;
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("1.7.7.6")]
-[assembly: AssemblyFileVersion("1.7.7.6")]
+[assembly: AssemblyVersion("1.7.7.7")]
+[assembly: AssemblyFileVersion("1.7.7.7")]
From 280445f61371fc5d702a39698107427a6c7386c0 Mon Sep 17 00:00:00 2001
From: CJKmkp <2564608840@qq.com>
Date: Sun, 24 Aug 2025 11:47:39 +0800
Subject: [PATCH 45/45] =?UTF-8?q?fix:=E6=B5=AE=E5=8A=A8=E6=A0=8F=E5=8A=A8?=
=?UTF-8?q?=E7=94=BB=E5=BC=82=E5=B8=B8?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../MainWindow_cs/MW_FloatingBarIcons.cs | 156 +++++++-----------
1 file changed, 57 insertions(+), 99 deletions(-)
diff --git a/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs b/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs
index c3e14fed..04a969da 100644
--- a/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs
+++ b/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs
@@ -27,7 +27,37 @@ namespace Ink_Canvas
{
public partial class MainWindow : Window
{
- #region “手勢"按鈕
+ #region 快捷键状态管理
+
+ ///
+ /// 统一的快捷键状态刷新方法
+ /// 在工具切换时调用,避免重复代码
+ ///
+ private void RefreshHotkeyState()
+ {
+ try
+ {
+ var hotkeyManagerField = this.GetType().GetField("_globalHotkeyManager",
+ System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
+ if (hotkeyManagerField != null)
+ {
+ var hotkeyManager = hotkeyManagerField.GetValue(this);
+ if (hotkeyManager != null)
+ {
+ var updateMethod = hotkeyManager.GetType().GetMethod("UpdateHotkeyRegistrationState");
+ updateMethod?.Invoke(hotkeyManager, null);
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"刷新快捷键状态时出错: {ex.Message}", LogHelper.LogType.Warning);
+ }
+ }
+
+ #endregion
+
+ #region "手勢"按鈕
///
/// 用於浮動工具欄的"手勢"按鈕和白板工具欄的"手勢"按鈕的點擊事件
@@ -706,26 +736,6 @@ namespace Ink_Canvas
SwitchToDefaultPen(null, null);
CheckColorTheme(true);
-
- // 更新快捷键注册状态
- try
- {
- var hotkeyManagerField = this.GetType().GetField("_globalHotkeyManager",
- System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
- if (hotkeyManagerField != null)
- {
- var hotkeyManager = hotkeyManagerField.GetValue(this);
- if (hotkeyManager != null)
- {
- var updateMethod = hotkeyManager.GetType().GetMethod("UpdateHotkeyRegistrationState");
- updateMethod?.Invoke(hotkeyManager, null);
- }
- }
- }
- catch (Exception ex)
- {
- LogHelper.WriteLogToFile($"更新快捷键状态时出错: {ex.Message}", LogHelper.LogType.Warning);
- }
}
#endregion
@@ -809,25 +819,8 @@ namespace Ink_Canvas
BtnSelect_Click(null, null);
HideSubPanels("select");
- // 更新快捷键注册状态
- try
- {
- var hotkeyManagerField = this.GetType().GetField("_globalHotkeyManager",
- System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
- if (hotkeyManagerField != null)
- {
- var hotkeyManager = hotkeyManagerField.GetValue(this);
- if (hotkeyManager != null)
- {
- var updateMethod = hotkeyManager.GetType().GetMethod("UpdateHotkeyRegistrationState");
- updateMethod?.Invoke(hotkeyManager, null);
- }
- }
- }
- catch (Exception ex)
- {
- LogHelper.WriteLogToFile($"更新快捷键状态时出错: {ex.Message}", LogHelper.LogType.Warning);
- }
+ // 工具切换完成后,统一刷新快捷键状态
+ RefreshHotkeyState();
}
#endregion
@@ -1655,26 +1648,6 @@ namespace Ink_Canvas
LogHelper.WriteLogToFile($"退出白板模式,恢复备份墨迹。当前模式:{(BtnPPTSlideShowEnd.Visibility == Visibility.Visible ? "PPT放映" : "桌面")}", LogHelper.LogType.Trace);
}
- // 更新快捷键注册状态
- try
- {
- var hotkeyManagerField = this.GetType().GetField("_globalHotkeyManager",
- System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
- if (hotkeyManagerField != null)
- {
- var hotkeyManager = hotkeyManagerField.GetValue(this);
- if (hotkeyManager != null)
- {
- var updateMethod = hotkeyManager.GetType().GetMethod("UpdateHotkeyRegistrationState");
- updateMethod?.Invoke(hotkeyManager, null);
- }
- }
- }
- catch (Exception ex)
- {
- LogHelper.WriteLogToFile($"更新快捷键状态时出错: {ex.Message}", LogHelper.LogType.Warning);
- }
-
if (BtnSwitchTheme.Content.ToString() == "浅色")
BtnSwitch.Content = "黑板";
else
@@ -1707,6 +1680,14 @@ namespace Ink_Canvas
else
ViewboxFloatingBarMarginAnimation(100, true);
}
+
+ // 工具切换完成后,统一刷新快捷键状态
+ RefreshHotkeyState();
+
+ if (BtnSwitchTheme.Content.ToString() == "浅色")
+ BtnSwitch.Content = "黑板";
+ else
+ BtnSwitch.Content = "白板";
}
internal void PenIcon_Click(object sender, RoutedEventArgs e)
@@ -1790,26 +1771,6 @@ namespace Ink_Canvas
}
}
- // 更新快捷键注册状态
- try
- {
- var hotkeyManagerField = this.GetType().GetField("_globalHotkeyManager",
- System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
- if (hotkeyManagerField != null)
- {
- var hotkeyManager = hotkeyManagerField.GetValue(this);
- if (hotkeyManager != null)
- {
- var updateMethod = hotkeyManager.GetType().GetMethod("UpdateHotkeyRegistrationState");
- updateMethod?.Invoke(hotkeyManager, null);
- }
- }
- }
- catch (Exception ex)
- {
- // 更新快捷键状态时出错
- }
-
// 修复:从线擦切换到批注时,保持之前的笔类型状态
// 如果之前是荧光笔模式,则保持荧光笔状态;否则重置为默认笔模式
forceEraser = false;
@@ -1938,6 +1899,14 @@ namespace Ink_Canvas
HideSubPanels("pen", true);
}
}
+
+ // 工具切换完成后,统一刷新快捷键状态
+ RefreshHotkeyState();
+
+ // 修复:从线擦切换到批注时,保持之前的笔类型状态
+ forceEraser = false;
+ forcePointEraser = false;
+ drawingShapeMode = 0;
}
private void ColorThemeSwitch_MouseUp(object sender, RoutedEventArgs e)
@@ -1991,25 +1960,8 @@ namespace Ink_Canvas
}
}
- // 更新快捷键注册状态
- try
- {
- var hotkeyManagerField = this.GetType().GetField("_globalHotkeyManager",
- System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
- if (hotkeyManagerField != null)
- {
- var hotkeyManager = hotkeyManagerField.GetValue(this);
- if (hotkeyManager != null)
- {
- var updateMethod = hotkeyManager.GetType().GetMethod("UpdateHotkeyRegistrationState");
- updateMethod?.Invoke(hotkeyManager, null);
- }
- }
- }
- catch (Exception ex)
- {
- LogHelper.WriteLogToFile($"更新快捷键状态时出错: {ex.Message}", LogHelper.LogType.Warning);
- }
+ // 工具切换完成后,统一刷新快捷键状态
+ RefreshHotkeyState();
}
private void BoardEraserIcon_Click(object sender, RoutedEventArgs e)
@@ -2044,6 +1996,9 @@ namespace Ink_Canvas
AnimationsHelper.HideWithSlideAndFade(EraserSizePanel);
}
}
+
+ // 工具切换完成后,统一刷新快捷键状态
+ RefreshHotkeyState();
}
private void EraserIconByStrokes_Click(object sender, RoutedEventArgs e)
@@ -2072,6 +2027,9 @@ namespace Ink_Canvas
CancelSingleFingerDragMode();
HideSubPanels("eraserByStrokes");
+
+ // 工具切换完成后,统一刷新快捷键状态
+ RefreshHotkeyState();
}
private void CursorWithDelIcon_Click(object sender, RoutedEventArgs e)