@@ -89,6 +89,15 @@
|
||||
"code",
|
||||
"design"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "Jursin",
|
||||
"name": "Jursin",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/127487914?v=4",
|
||||
"profile": "http://blog.jursin.top",
|
||||
"contributions": [
|
||||
"design"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@
|
||||
xmlns:local="clr-namespace:Ink_Canvas"
|
||||
xmlns:tb="http://www.hardcodet.net/taskbar"
|
||||
xmlns:ui="http://schemas.inkore.net/lib/ui/wpf/modern"
|
||||
StartupUri="MainWindow.xaml">
|
||||
>
|
||||
<Application.Resources>
|
||||
<ResourceDictionary>
|
||||
<Style TargetType="ui:ScrollViewerEx">
|
||||
|
||||
+194
-16
@@ -76,7 +76,12 @@ namespace Ink_Canvas
|
||||
InitializeCrashListeners();
|
||||
|
||||
// 仅在崩溃后操作为静默重启时才启动看门狗
|
||||
if (CrashAction == CrashActionType.SilentRestart)
|
||||
// 在更新模式下不启动看门狗,避免干扰更新流程
|
||||
args = Environment.GetCommandLineArgs();
|
||||
bool isUpdateMode = args.Contains("--update-mode");
|
||||
bool isFinalApp = args.Contains("--final-app");
|
||||
|
||||
if (CrashAction == CrashActionType.SilentRestart && !isUpdateMode && !isFinalApp)
|
||||
{
|
||||
StartWatchdogIfNeeded();
|
||||
}
|
||||
@@ -465,6 +470,16 @@ namespace Ink_Canvas
|
||||
RootPath = AppDomain.CurrentDomain.SetupInformation.ApplicationBase;
|
||||
|
||||
LogHelper.NewLog(string.Format("Ink Canvas Starting (Version: {0})", Assembly.GetExecutingAssembly().GetName().Version));
|
||||
|
||||
// 检查是否为最终应用启动(更新后的应用)
|
||||
bool isFinalApp = e.Args.Contains("--final-app");
|
||||
bool skipMutexCheck = e.Args.Contains("--skip-mutex-check");
|
||||
|
||||
// 记录最终应用启动状态
|
||||
if (isFinalApp)
|
||||
{
|
||||
LogHelper.WriteLogToFile("App | 检测到最终应用启动(更新后的应用)");
|
||||
}
|
||||
|
||||
// 在应用启动时自动释放IACore相关DLL
|
||||
try
|
||||
@@ -482,32 +497,195 @@ namespace Ink_Canvas
|
||||
LogHelper.WriteLogToFile($"App | 使用频率: {DeviceIdentifier.GetUsageFrequency()}");
|
||||
LogHelper.WriteLogToFile($"App | 更新优先级: {DeviceIdentifier.GetUpdatePriority()}");
|
||||
|
||||
bool ret;
|
||||
mutex = new Mutex(true, "InkCanvasForClass CE", out ret);
|
||||
|
||||
if (!ret && !e.Args.Contains("-m")) //-m multiple
|
||||
// 处理更新模式启动
|
||||
bool isUpdateMode = AutoUpdateHelper.HandleUpdateModeStartup(e.Args);
|
||||
|
||||
// 如果是更新模式,不显示主窗口但保持应用运行
|
||||
if (isUpdateMode)
|
||||
{
|
||||
LogHelper.WriteLogToFile("App | 检测到更新模式,跳过主窗口显示,保持应用运行");
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查是否存在更新标记文件
|
||||
string updateMarkerFile = Path.Combine(App.RootPath, "update_in_progress.tmp");
|
||||
bool isUpdateInProgress = false;
|
||||
|
||||
// 检查是否以更新模式启动
|
||||
isUpdateMode = e.Args.Contains("--update-mode");
|
||||
|
||||
// 如果是最终应用启动,立即清理更新标记文件
|
||||
if (isFinalApp)
|
||||
{
|
||||
LogHelper.NewLog("Detected existing instance");
|
||||
MessageBox.Show("已有一个程序实例正在运行");
|
||||
LogHelper.NewLog("Ink Canvas automatically closed");
|
||||
IsAppExitByUser = true; // 多开时标记为用户主动退出
|
||||
// 写入退出信号,确保看门狗不会重启
|
||||
try
|
||||
{
|
||||
StartupCount.Reset();
|
||||
File.WriteAllText(watchdogExitSignalFile, "exit");
|
||||
if (watchdogProcess != null && !watchdogProcess.HasExited)
|
||||
if (File.Exists(updateMarkerFile))
|
||||
{
|
||||
watchdogProcess.Kill();
|
||||
File.Delete(updateMarkerFile);
|
||||
LogHelper.WriteLogToFile("App | 最终应用启动,清理更新标记文件");
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
Environment.Exit(0);
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.WriteLogToFile($"App | 清理更新标记文件失败: {ex.Message}", LogHelper.LogType.Warning);
|
||||
}
|
||||
}
|
||||
|
||||
// 如果不是最终应用启动,才检查更新标记文件
|
||||
if (!isFinalApp && File.Exists(updateMarkerFile))
|
||||
{
|
||||
try
|
||||
{
|
||||
string updateProcessIdStr = File.ReadAllText(updateMarkerFile).Trim();
|
||||
if (int.TryParse(updateProcessIdStr, out int updateProcessId))
|
||||
{
|
||||
LogHelper.WriteLogToFile($"App | 检测到更新标记文件,更新进程ID: {updateProcessId}");
|
||||
|
||||
// 检查更新进程是否还在运行
|
||||
try
|
||||
{
|
||||
Process updateProcess = Process.GetProcessById(updateProcessId);
|
||||
if (!updateProcess.HasExited)
|
||||
{
|
||||
LogHelper.WriteLogToFile("App | 更新进程仍在运行,等待更新完成");
|
||||
isUpdateInProgress = true;
|
||||
|
||||
// 等待更新进程完成
|
||||
int waitCount = 0;
|
||||
const int maxWaitCount = 10; // 减少等待时间到10秒
|
||||
|
||||
while (waitCount < maxWaitCount && !updateProcess.HasExited)
|
||||
{
|
||||
Thread.Sleep(500); // 减少等待间隔到500ms
|
||||
waitCount++;
|
||||
LogHelper.WriteLogToFile($"App | 等待更新进程完成... ({waitCount}/{maxWaitCount})");
|
||||
}
|
||||
|
||||
if (updateProcess.HasExited)
|
||||
{
|
||||
LogHelper.WriteLogToFile("App | 更新进程已结束");
|
||||
}
|
||||
else
|
||||
{
|
||||
LogHelper.WriteLogToFile("App | 等待更新进程超时,强制清理", LogHelper.LogType.Warning);
|
||||
// 超时后强制清理标记文件
|
||||
try
|
||||
{
|
||||
if (File.Exists(updateMarkerFile))
|
||||
{
|
||||
File.Delete(updateMarkerFile);
|
||||
LogHelper.WriteLogToFile("App | 强制清理更新标记文件");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.WriteLogToFile($"App | 强制清理更新标记文件失败: {ex.Message}", LogHelper.LogType.Warning);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LogHelper.WriteLogToFile("App | 更新进程已结束");
|
||||
}
|
||||
}
|
||||
catch (ArgumentException)
|
||||
{
|
||||
LogHelper.WriteLogToFile("App | 更新进程已不存在");
|
||||
}
|
||||
|
||||
// 无论更新进程是否还在运行,都清理标记文件
|
||||
try
|
||||
{
|
||||
if (File.Exists(updateMarkerFile))
|
||||
{
|
||||
File.Delete(updateMarkerFile);
|
||||
LogHelper.WriteLogToFile("App | 清理更新标记文件");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.WriteLogToFile($"App | 清理更新标记文件失败: {ex.Message}", LogHelper.LogType.Warning);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.WriteLogToFile($"App | 读取更新标记文件失败: {ex.Message}", LogHelper.LogType.Warning);
|
||||
// 如果读取失败,也尝试删除标记文件
|
||||
try
|
||||
{
|
||||
if (File.Exists(updateMarkerFile))
|
||||
{
|
||||
File.Delete(updateMarkerFile);
|
||||
LogHelper.WriteLogToFile("App | 清理损坏的更新标记文件");
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
}
|
||||
|
||||
// 如果是更新过程、更新模式、最终应用或跳过Mutex检查,跳过Mutex检查
|
||||
if (!isUpdateInProgress && !isUpdateMode && !isFinalApp && !skipMutexCheck)
|
||||
{
|
||||
bool ret;
|
||||
mutex = new Mutex(true, "InkCanvasForClass CE", out ret);
|
||||
|
||||
if (!ret && !e.Args.Contains("-m")) //-m multiple
|
||||
{
|
||||
LogHelper.NewLog("Detected existing instance");
|
||||
MessageBox.Show("已有一个程序实例正在运行");
|
||||
LogHelper.NewLog("Ink Canvas automatically closed");
|
||||
IsAppExitByUser = true; // 多开时标记为用户主动退出
|
||||
// 写入退出信号,确保看门狗不会重启
|
||||
try
|
||||
{
|
||||
StartupCount.Reset();
|
||||
File.WriteAllText(watchdogExitSignalFile, "exit");
|
||||
if (watchdogProcess != null && !watchdogProcess.HasExited)
|
||||
{
|
||||
watchdogProcess.Kill();
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
Environment.Exit(0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (isUpdateMode)
|
||||
{
|
||||
LogHelper.WriteLogToFile("App | 更新模式启动,跳过重复运行检测");
|
||||
}
|
||||
else if (isFinalApp)
|
||||
{
|
||||
LogHelper.WriteLogToFile("App | 最终应用启动,跳过重复运行检测");
|
||||
}
|
||||
else if (skipMutexCheck)
|
||||
{
|
||||
LogHelper.WriteLogToFile("App | 跳过Mutex检查模式启动,跳过重复运行检测");
|
||||
}
|
||||
else
|
||||
{
|
||||
LogHelper.WriteLogToFile("App | 更新过程中,跳过重复运行检测");
|
||||
}
|
||||
|
||||
// 在特殊模式下,创建一个临时的Mutex以避免其他检查出错
|
||||
string mutexName = isFinalApp ? "InkCanvasForClass CE Final" : "InkCanvasForClass CE Update";
|
||||
mutex = new Mutex(true, mutexName, out bool tempRet);
|
||||
|
||||
// 额外等待一小段时间确保更新进程完全退出
|
||||
Thread.Sleep(1000);
|
||||
LogHelper.WriteLogToFile("App | 特殊模式等待完成,继续启动");
|
||||
}
|
||||
|
||||
_taskbar = (TaskbarIcon)FindResource("TaskbarTrayIcon");
|
||||
|
||||
StartArgs = e.Args;
|
||||
|
||||
// 在非更新模式下创建主窗口
|
||||
var mainWindow = new MainWindow();
|
||||
MainWindow = mainWindow;
|
||||
mainWindow.Show();
|
||||
|
||||
// 新增:Office注册表检测
|
||||
try
|
||||
|
||||
@@ -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.8.0")]
|
||||
[assembly: AssemblyFileVersion("1.7.8.0")]
|
||||
[assembly: AssemblyVersion("1.7.8.3")]
|
||||
[assembly: AssemblyFileVersion("1.7.8.3")]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
@@ -28,6 +28,9 @@ namespace Ink_Canvas.Helpers
|
||||
private static readonly string updatesFolderPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "AutoUpdate");
|
||||
private static string statusFilePath;
|
||||
|
||||
// GitHub Token认证
|
||||
private static readonly string GitHubToken = "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";
|
||||
|
||||
// 线路组结构体(包含版本、下载、日志地址)
|
||||
public class UpdateLineGroup
|
||||
{
|
||||
@@ -45,9 +48,9 @@ namespace Ink_Canvas.Helpers
|
||||
new UpdateLineGroup
|
||||
{
|
||||
GroupName = "GitHub主线",
|
||||
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"
|
||||
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"
|
||||
},
|
||||
new UpdateLineGroup
|
||||
{
|
||||
@@ -67,11 +70,13 @@ namespace Ink_Canvas.Helpers
|
||||
{
|
||||
GroupName = "智教联盟",
|
||||
DownloadUrlFormat = "https://get.smart-teach.cn/d/Ningbo-S3/shared/jiangling/community/InkCanvasForClass.CE.{0}.zip",
|
||||
LogUrl = "https://bgithub.xyz/InkCanvasForClass/community/raw/refs/heads/main/UpdateLog.md"
|
||||
},
|
||||
new UpdateLineGroup
|
||||
{
|
||||
GroupName = "inkeys",
|
||||
DownloadUrlFormat = "https://iccce.inkeys.top/Release/InkCanvasForClass.CE.{0}.zip",
|
||||
LogUrl = "https://bgithub.xyz/InkCanvasForClass/community/raw/refs/heads/main/UpdateLog.md"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -80,9 +85,9 @@ namespace Ink_Canvas.Helpers
|
||||
new UpdateLineGroup
|
||||
{
|
||||
GroupName = "GitHub主线",
|
||||
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"
|
||||
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"
|
||||
},
|
||||
new UpdateLineGroup
|
||||
{
|
||||
@@ -102,11 +107,13 @@ namespace Ink_Canvas.Helpers
|
||||
{
|
||||
GroupName = "智教联盟",
|
||||
DownloadUrlFormat = "https://get.smart-teach.cn/d/Ningbo-S3/shared/jiangling/community-beta/InkCanvasForClass.CE.{0}.zip",
|
||||
LogUrl = "https://bgithub.xyz/InkCanvasForClass/community-beta/raw/refs/heads/main/UpdateLog.md"
|
||||
},
|
||||
new UpdateLineGroup
|
||||
{
|
||||
GroupName = "inkeys",
|
||||
DownloadUrlFormat = "https://iccce.inkeys.top/Beta/InkCanvasForClass.CE.{0}.zip",
|
||||
LogUrl = "https://bgithub.xyz/InkCanvasForClass/community-beta/raw/refs/heads/main/UpdateLog.md"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -409,6 +416,8 @@ namespace Ink_Canvas.Helpers
|
||||
using (var client = new HttpClient())
|
||||
{
|
||||
client.DefaultRequestHeaders.Add("User-Agent", "ICC-CE Auto Updater");
|
||||
client.DefaultRequestHeaders.Add("Authorization", $"token {GitHubToken}");
|
||||
LogHelper.WriteLogToFile("AutoUpdate | 使用GitHub Token进行API调用");
|
||||
var response = await client.GetStringAsync(apiUrl);
|
||||
var releases = JArray.Parse(response);
|
||||
|
||||
@@ -450,6 +459,8 @@ namespace Ink_Canvas.Helpers
|
||||
using (var client = new HttpClient())
|
||||
{
|
||||
client.DefaultRequestHeaders.Add("User-Agent", "ICC-CE Auto Updater");
|
||||
client.DefaultRequestHeaders.Add("Authorization", $"token {GitHubToken}");
|
||||
LogHelper.WriteLogToFile("AutoUpdate | 使用GitHub Token进行API调用");
|
||||
var response = await client.GetStringAsync(apiUrl);
|
||||
var json = JObject.Parse(response);
|
||||
string version = json["tag_name"]?.ToString();
|
||||
@@ -1130,7 +1141,7 @@ namespace Ink_Canvas.Helpers
|
||||
}
|
||||
}
|
||||
|
||||
// 安装新版本应用
|
||||
// 安装新版本应用 - 优化版本,不使用命令行
|
||||
public static void InstallNewVersionApp(string version, bool isInSilence)
|
||||
{
|
||||
try
|
||||
@@ -1183,113 +1194,109 @@ namespace Ink_Canvas.Helpers
|
||||
LogHelper.WriteLogToFile($"AutoUpdate | ZIP文件大小: {fileInfo.Length} 字节");
|
||||
|
||||
string currentAppDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
|
||||
int currentProcessId = Process.GetCurrentProcess().Id;
|
||||
string appPath = Assembly.GetExecutingAssembly().Location;
|
||||
int currentProcessId = Process.GetCurrentProcess().Id;
|
||||
|
||||
LogHelper.WriteLogToFile($"AutoUpdate | 当前应用程序目录: {currentAppDir}");
|
||||
LogHelper.WriteLogToFile($"AutoUpdate | 当前进程ID: {currentProcessId}");
|
||||
LogHelper.WriteLogToFile($"AutoUpdate | 静默更新模式: {isInSilence}");
|
||||
|
||||
string batchFilePath = Path.Combine(Path.GetTempPath(), "UpdateICC_" + Guid.NewGuid().ToString().Substring(0, 8) + ".bat");
|
||||
LogHelper.WriteLogToFile($"AutoUpdate | 创建更新批处理文件: {batchFilePath}");
|
||||
|
||||
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\"");
|
||||
|
||||
string updateBatPath = Path.Combine(Path.GetTempPath(), "ICCUpdate_" + Guid.NewGuid().ToString().Substring(0, 8) + ".bat");
|
||||
batchContent.AppendLine($"echo @echo off > \"{updateBatPath}\"");
|
||||
batchContent.AppendLine($"echo set PROC_ID={currentProcessId} >> \"{updateBatPath}\"");
|
||||
batchContent.AppendLine($"echo :CHECK_PROCESS >> \"{updateBatPath}\"");
|
||||
batchContent.AppendLine($"echo tasklist /fi \"PID eq %PROC_ID%\" ^| find \"%PROC_ID%\" ^> nul >> \"{updateBatPath}\"");
|
||||
batchContent.AppendLine($"echo if %%ERRORLEVEL%% == 0 ( >> \"{updateBatPath}\"");
|
||||
batchContent.AppendLine($"echo timeout /t 1 /nobreak ^> nul >> \"{updateBatPath}\"");
|
||||
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}\"");
|
||||
|
||||
// 创建解压目录
|
||||
string extractPath = Path.Combine(updatesFolderPath, $"Extract_{version}");
|
||||
batchContent.AppendLine($"echo echo Extracting update files... >> \"{updateBatPath}\"");
|
||||
batchContent.AppendLine($"echo if exist \"{extractPath}\" rd /s /q \"{extractPath}\" >> \"{updateBatPath}\"");
|
||||
batchContent.AppendLine($"echo mkdir \"{extractPath}\" >> \"{updateBatPath}\"");
|
||||
|
||||
batchContent.AppendLine($"echo powershell -command \"Expand-Archive -Path '{zipFilePath.Replace("'", "''")}' -DestinationPath '{extractPath.Replace("'", "''")}' -Force\" >> \"{updateBatPath}\"");
|
||||
batchContent.AppendLine($"echo if %%ERRORLEVEL%% neq 0 ( >> \"{updateBatPath}\"");
|
||||
batchContent.AppendLine($"echo goto ERROR_EXIT >> \"{updateBatPath}\"");
|
||||
batchContent.AppendLine($"echo ) >> \"{updateBatPath}\"");
|
||||
|
||||
batchContent.AppendLine($"echo echo Copying updated files to application directory... >> \"{updateBatPath}\"");
|
||||
batchContent.AppendLine($"echo xcopy /s /y /e \"{extractPath}\\*\" \"{currentAppDir}\\\" >> \"{updateBatPath}\"");
|
||||
batchContent.AppendLine($"echo if %%ERRORLEVEL%% neq 0 ( >> \"{updateBatPath}\"");
|
||||
batchContent.AppendLine($"echo goto ERROR_EXIT >> \"{updateBatPath}\"");
|
||||
batchContent.AppendLine($"echo ) >> \"{updateBatPath}\"");
|
||||
|
||||
batchContent.AppendLine($"echo echo Cleaning up temporary files... >> \"{updateBatPath}\"");
|
||||
batchContent.AppendLine($"echo if exist \"{extractPath}\" rd /s /q \"{extractPath}\" >> \"{updateBatPath}\"");
|
||||
batchContent.AppendLine($"echo if exist \"{zipFilePath}\" del /f /q \"{zipFilePath}\" >> \"{updateBatPath}\"");
|
||||
|
||||
batchContent.AppendLine($"echo echo Update completed successfully! >> \"{updateBatPath}\"");
|
||||
|
||||
if (isInSilence)
|
||||
if (Directory.Exists(extractPath))
|
||||
{
|
||||
batchContent.AppendLine($"echo echo 自动启动应用程序... >> \"{updateBatPath}\"");
|
||||
batchContent.AppendLine($"echo start \"\" \"{appPath}\" >> \"{updateBatPath}\"");
|
||||
}
|
||||
else
|
||||
{
|
||||
batchContent.AppendLine($"echo taskkill /F /IM \"InkCanvasForClass.exe\" >nul 2>nul >> \"{updateBatPath}\"");
|
||||
batchContent.AppendLine($"echo :: 检查应用程序是否已经在运行 >> \"{updateBatPath}\"");
|
||||
batchContent.AppendLine($"echo tasklist /FI \"IMAGENAME eq InkCanvasForClass.exe\" | find /i \"InkCanvasForClass.exe\" > nul >> \"{updateBatPath}\"");
|
||||
batchContent.AppendLine($"echo if %%ERRORLEVEL%% neq 0 ( >> \"{updateBatPath}\"");
|
||||
batchContent.AppendLine($"echo echo 启动应用程序... >> \"{updateBatPath}\"");
|
||||
batchContent.AppendLine($"echo start \"\" \"{appPath}\" >> \"{updateBatPath}\"");
|
||||
batchContent.AppendLine($"echo ) else ( >> \"{updateBatPath}\"");
|
||||
batchContent.AppendLine($"echo echo 应用程序已经在运行,不再重复启动 >> \"{updateBatPath}\"");
|
||||
batchContent.AppendLine($"echo ) >> \"{updateBatPath}\"");
|
||||
try
|
||||
{
|
||||
Directory.Delete(extractPath, true);
|
||||
LogHelper.WriteLogToFile($"AutoUpdate | 清理已存在的解压目录: {extractPath}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.WriteLogToFile($"AutoUpdate | 清理解压目录失败: {ex.Message}", LogHelper.LogType.Warning);
|
||||
}
|
||||
}
|
||||
|
||||
batchContent.AppendLine($"echo exit /b 0 >> \"{updateBatPath}\"");
|
||||
batchContent.AppendLine($"echo goto EXIT >> \"{updateBatPath}\"");
|
||||
|
||||
if (isInSilence)
|
||||
try
|
||||
{
|
||||
batchContent.AppendLine($"echo :ERROR_EXIT >> \"{updateBatPath}\"");
|
||||
batchContent.AppendLine($"echo echo Update failed! >> \"%temp%\\icc_update_error.log\" >> \"{updateBatPath}\"");
|
||||
batchContent.AppendLine($"echo exit /b 1 >> \"{updateBatPath}\"");
|
||||
Directory.CreateDirectory(extractPath);
|
||||
LogHelper.WriteLogToFile($"AutoUpdate | 创建解压目录: {extractPath}");
|
||||
}
|
||||
else
|
||||
catch (Exception ex)
|
||||
{
|
||||
batchContent.AppendLine($"echo :ERROR_EXIT >> \"{updateBatPath}\"");
|
||||
batchContent.AppendLine($"echo start \"\" cmd /c \"echo Update failed! ^& pause\" >> \"{updateBatPath}\"");
|
||||
batchContent.AppendLine($"echo exit /b 1 >> \"{updateBatPath}\"");
|
||||
LogHelper.WriteLogToFile($"AutoUpdate | 创建解压目录失败: {ex.Message}", LogHelper.LogType.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
batchContent.AppendLine($"echo :EXIT >> \"{updateBatPath}\"");
|
||||
batchContent.AppendLine($"echo del \"{updateBatPath}\" >> \"{updateBatPath}\"");
|
||||
batchContent.AppendLine($"echo exit >> \"{updateBatPath}\"");
|
||||
|
||||
batchContent.AppendLine($"wscript \"%temp%\\hideme.vbs\" \"{updateBatPath}\"");
|
||||
batchContent.AppendLine("del \"%temp%\\hideme.vbs\"");
|
||||
batchContent.AppendLine("exit");
|
||||
|
||||
File.WriteAllText(batchFilePath, batchContent.ToString());
|
||||
LogHelper.WriteLogToFile("AutoUpdate | 创建更新批处理文件完成");
|
||||
|
||||
Process.Start(new ProcessStartInfo
|
||||
// 解压ZIP文件
|
||||
try
|
||||
{
|
||||
FileName = batchFilePath,
|
||||
CreateNoWindow = true,
|
||||
UseShellExecute = true,
|
||||
WindowStyle = ProcessWindowStyle.Hidden
|
||||
});
|
||||
LogHelper.WriteLogToFile($"AutoUpdate | 开始解压ZIP文件到: {extractPath}");
|
||||
ZipFile.ExtractToDirectory(zipFilePath, extractPath);
|
||||
LogHelper.WriteLogToFile("AutoUpdate | ZIP文件解压完成");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.WriteLogToFile($"AutoUpdate | 解压ZIP文件失败: {ex.Message}", LogHelper.LogType.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
LogHelper.WriteLogToFile("AutoUpdate | 启动更新批处理进程(隐藏窗口)");
|
||||
// 查找解压后的主程序文件
|
||||
string newAppPath = null;
|
||||
string[] possibleExeNames = { "InkCanvasForClass.exe", "Ink Canvas.exe", "InkCanvas.exe" };
|
||||
|
||||
foreach (string exeName in possibleExeNames)
|
||||
{
|
||||
string testPath = Path.Combine(extractPath, exeName);
|
||||
if (File.Exists(testPath))
|
||||
{
|
||||
newAppPath = testPath;
|
||||
LogHelper.WriteLogToFile($"AutoUpdate | 找到新版本主程序: {newAppPath}");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(newAppPath))
|
||||
{
|
||||
LogHelper.WriteLogToFile("AutoUpdate | 在解压目录中未找到主程序文件", LogHelper.LogType.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
// 启动新版本进程
|
||||
try
|
||||
{
|
||||
LogHelper.WriteLogToFile($"AutoUpdate | 准备启动新版本进程: {newAppPath}");
|
||||
|
||||
// 启动新版本进程(以更新模式)
|
||||
string arguments = $"--update-mode --old-process-id={currentProcessId} --extract-path=\"{extractPath}\" --target-path=\"{currentAppDir}\" --is-silence={isInSilence}";
|
||||
|
||||
LogHelper.WriteLogToFile($"AutoUpdate | 启动新进程的命令行: {newAppPath} {arguments}");
|
||||
|
||||
ProcessStartInfo startInfo = new ProcessStartInfo
|
||||
{
|
||||
FileName = newAppPath,
|
||||
Arguments = arguments,
|
||||
UseShellExecute = false,
|
||||
CreateNoWindow = false
|
||||
};
|
||||
|
||||
Process.Start(startInfo);
|
||||
LogHelper.WriteLogToFile("AutoUpdate | 新版本进程启动命令已执行");
|
||||
|
||||
// 等待一小段时间确保新进程启动
|
||||
Thread.Sleep(2000);
|
||||
|
||||
// 关闭当前旧软件进程
|
||||
LogHelper.WriteLogToFile("AutoUpdate | 关闭当前旧软件进程");
|
||||
App.IsAppExitByUser = true;
|
||||
Application.Current.Dispatcher.Invoke(() =>
|
||||
{
|
||||
Application.Current.Shutdown();
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.WriteLogToFile($"AutoUpdate | 启动新版本进程时出错: {ex.Message}", LogHelper.LogType.Error);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -1301,6 +1308,421 @@ namespace Ink_Canvas.Helpers
|
||||
}
|
||||
}
|
||||
|
||||
// 处理更新模式的启动参数
|
||||
public static bool HandleUpdateModeStartup(string[] args)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 检查是否以更新模式启动
|
||||
if (args.Contains("--update-mode"))
|
||||
{
|
||||
LogHelper.WriteLogToFile("AutoUpdate | 检测到更新模式启动");
|
||||
|
||||
// 解析命令行参数
|
||||
int oldProcessId = -1;
|
||||
string extractPath = null;
|
||||
string targetPath = null;
|
||||
bool isSilence = false;
|
||||
|
||||
// 记录所有参数用于调试
|
||||
LogHelper.WriteLogToFile($"AutoUpdate | 接收到的命令行参数: {string.Join(" ", args)}");
|
||||
|
||||
for (int i = 0; i < args.Length; i++)
|
||||
{
|
||||
string arg = args[i];
|
||||
LogHelper.WriteLogToFile($"AutoUpdate | 处理参数 {i}: {arg}");
|
||||
|
||||
if (arg.StartsWith("--old-process-id="))
|
||||
{
|
||||
string processIdStr = arg.Substring("--old-process-id=".Length);
|
||||
if (int.TryParse(processIdStr, out int pid))
|
||||
{
|
||||
oldProcessId = pid;
|
||||
LogHelper.WriteLogToFile($"AutoUpdate | 解析到老进程ID: {oldProcessId}");
|
||||
}
|
||||
}
|
||||
else if (arg.StartsWith("--extract-path="))
|
||||
{
|
||||
extractPath = arg.Substring("--extract-path=".Length).Trim('"');
|
||||
LogHelper.WriteLogToFile($"AutoUpdate | 解析到解压路径: {extractPath}");
|
||||
}
|
||||
else if (arg.StartsWith("--target-path="))
|
||||
{
|
||||
targetPath = arg.Substring("--target-path=".Length).Trim('"');
|
||||
LogHelper.WriteLogToFile($"AutoUpdate | 解析到目标路径: {targetPath}");
|
||||
}
|
||||
else if (arg.StartsWith("--is-silence="))
|
||||
{
|
||||
string silenceStr = arg.Substring("--is-silence=".Length);
|
||||
if (bool.TryParse(silenceStr, out bool silence))
|
||||
{
|
||||
isSilence = silence;
|
||||
LogHelper.WriteLogToFile($"AutoUpdate | 解析到静默模式: {isSilence}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LogHelper.WriteLogToFile($"AutoUpdate | 更新参数 - 老进程ID: {oldProcessId}, 解压路径: {extractPath}, 目标路径: {targetPath}, 静默模式: {isSilence}");
|
||||
|
||||
if (oldProcessId > 0 && !string.IsNullOrEmpty(extractPath) && !string.IsNullOrEmpty(targetPath))
|
||||
{
|
||||
LogHelper.WriteLogToFile($"AutoUpdate | 参数验证通过,启动更新任务");
|
||||
// 启动更新任务
|
||||
Task.Run(async () => await PerformUpdate(oldProcessId, extractPath, targetPath, isSilence));
|
||||
return true; // 返回true表示是更新模式
|
||||
}
|
||||
else
|
||||
{
|
||||
LogHelper.WriteLogToFile($"AutoUpdate | 参数验证失败 - 老进程ID: {oldProcessId}, 解压路径: {extractPath}, 目标路径: {targetPath}", LogHelper.LogType.Error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false; // 返回false表示不是更新模式
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.WriteLogToFile($"AutoUpdate | 处理更新模式启动时出错: {ex.Message}", LogHelper.LogType.Error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 执行实际的更新操作
|
||||
private static async Task PerformUpdate(int oldProcessId, string extractPath, string targetPath, bool isSilence)
|
||||
{
|
||||
try
|
||||
{
|
||||
LogHelper.WriteLogToFile("AutoUpdate | 开始执行更新操作");
|
||||
|
||||
// 等待老进程完全退出
|
||||
LogHelper.WriteLogToFile($"AutoUpdate | 等待老进程 {oldProcessId} 退出");
|
||||
int waitCount = 0;
|
||||
const int maxWaitCount = 30; // 最多等待30秒
|
||||
|
||||
while (waitCount < maxWaitCount)
|
||||
{
|
||||
try
|
||||
{
|
||||
Process oldProcess = Process.GetProcessById(oldProcessId);
|
||||
if (oldProcess.HasExited)
|
||||
{
|
||||
LogHelper.WriteLogToFile("AutoUpdate | 老进程已退出");
|
||||
break;
|
||||
}
|
||||
LogHelper.WriteLogToFile($"AutoUpdate | 老进程仍在运行,等待中... ({waitCount + 1}/{maxWaitCount})");
|
||||
Thread.Sleep(1000);
|
||||
waitCount++;
|
||||
}
|
||||
catch (ArgumentException)
|
||||
{
|
||||
// 进程不存在,说明已经退出
|
||||
LogHelper.WriteLogToFile("AutoUpdate | 老进程已退出(进程不存在)");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (waitCount >= maxWaitCount)
|
||||
{
|
||||
LogHelper.WriteLogToFile("AutoUpdate | 等待老进程退出超时,尝试强制结束", LogHelper.LogType.Warning);
|
||||
try
|
||||
{
|
||||
Process oldProcess = Process.GetProcessById(oldProcessId);
|
||||
oldProcess.Kill();
|
||||
Thread.Sleep(2000); // 等待进程完全结束
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.WriteLogToFile($"AutoUpdate | 强制结束老进程失败: {ex.Message}", LogHelper.LogType.Warning);
|
||||
}
|
||||
}
|
||||
|
||||
// 确保目标目录存在
|
||||
if (!Directory.Exists(targetPath))
|
||||
{
|
||||
Directory.CreateDirectory(targetPath);
|
||||
LogHelper.WriteLogToFile($"AutoUpdate | 创建目标目录: {targetPath}");
|
||||
}
|
||||
|
||||
// 复制文件到目标目录
|
||||
LogHelper.WriteLogToFile($"AutoUpdate | 开始复制文件从 {extractPath} 到 {targetPath}");
|
||||
|
||||
try
|
||||
{
|
||||
// 使用递归复制方法,支持重试机制
|
||||
bool copySuccess = await CopyDirectoryWithRetryAsync(extractPath, targetPath);
|
||||
if (copySuccess)
|
||||
{
|
||||
LogHelper.WriteLogToFile("AutoUpdate | 文件复制完成");
|
||||
}
|
||||
else
|
||||
{
|
||||
LogHelper.WriteLogToFile("AutoUpdate | 文件复制失败,部分文件可能无法覆盖", LogHelper.LogType.Error);
|
||||
|
||||
if (!isSilence)
|
||||
{
|
||||
MessageBox.Show("更新失败:部分文件无法覆盖,可能是文件正在使用中。\n请关闭所有相关程序后重试。", "更新失败", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.WriteLogToFile($"AutoUpdate | 文件复制失败: {ex.Message}", LogHelper.LogType.Error);
|
||||
|
||||
if (!isSilence)
|
||||
{
|
||||
MessageBox.Show($"更新失败:文件复制时出错\n{ex.Message}", "更新失败", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 清理临时文件
|
||||
try
|
||||
{
|
||||
LogHelper.WriteLogToFile("AutoUpdate | 清理临时文件");
|
||||
|
||||
// 删除解压目录
|
||||
if (Directory.Exists(extractPath))
|
||||
{
|
||||
Directory.Delete(extractPath, true);
|
||||
LogHelper.WriteLogToFile($"AutoUpdate | 删除解压目录: {extractPath}");
|
||||
}
|
||||
|
||||
// 删除ZIP文件
|
||||
string zipFile = Path.Combine(updatesFolderPath, $"InkCanvasForClass.CE.*.zip");
|
||||
string[] zipFiles = Directory.GetFiles(updatesFolderPath, "InkCanvasForClass.CE.*.zip");
|
||||
foreach (string zip in zipFiles)
|
||||
{
|
||||
try
|
||||
{
|
||||
File.Delete(zip);
|
||||
LogHelper.WriteLogToFile($"AutoUpdate | 删除ZIP文件: {zip}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.WriteLogToFile($"AutoUpdate | 删除ZIP文件失败: {ex.Message}", LogHelper.LogType.Warning);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.WriteLogToFile($"AutoUpdate | 清理临时文件时出错: {ex.Message}", LogHelper.LogType.Warning);
|
||||
}
|
||||
|
||||
LogHelper.WriteLogToFile("AutoUpdate | 更新操作完成");
|
||||
|
||||
// 启动更新后的应用程序
|
||||
string newAppPath = Path.Combine(targetPath, "InkCanvasForClass.exe");
|
||||
if (File.Exists(newAppPath))
|
||||
{
|
||||
try
|
||||
{
|
||||
LogHelper.WriteLogToFile($"AutoUpdate | 准备启动更新后的应用程序: {newAppPath}");
|
||||
|
||||
// 获取当前更新进程ID
|
||||
int currentUpdateProcessId = Process.GetCurrentProcess().Id;
|
||||
LogHelper.WriteLogToFile($"AutoUpdate | 当前更新进程ID: {currentUpdateProcessId}");
|
||||
|
||||
// 创建一个临时标记文件,用于新进程检测更新状态
|
||||
string updateMarkerFile = Path.Combine(targetPath, "update_in_progress.tmp");
|
||||
File.WriteAllText(updateMarkerFile, currentUpdateProcessId.ToString());
|
||||
LogHelper.WriteLogToFile($"AutoUpdate | 创建更新标记文件: {updateMarkerFile}");
|
||||
|
||||
// 启动更新后的应用程序(标记为最终应用,不受相同进程影响)
|
||||
ProcessStartInfo startInfo = new ProcessStartInfo
|
||||
{
|
||||
FileName = newAppPath,
|
||||
Arguments = "--final-app --skip-mutex-check",
|
||||
WorkingDirectory = targetPath,
|
||||
UseShellExecute = false
|
||||
};
|
||||
|
||||
Process newProcess = Process.Start(startInfo);
|
||||
LogHelper.WriteLogToFile($"AutoUpdate | 最终应用程序启动成功,PID: {newProcess?.Id},已标记为最终应用");
|
||||
|
||||
// 等待一小段时间确保最终应用程序启动
|
||||
Thread.Sleep(2000);
|
||||
|
||||
// 结束当前更新进程
|
||||
LogHelper.WriteLogToFile("AutoUpdate | 更新流程完成,结束更新进程");
|
||||
|
||||
// 强制结束当前更新进程
|
||||
try
|
||||
{
|
||||
LogHelper.WriteLogToFile("AutoUpdate | 强制结束更新进程");
|
||||
|
||||
// 标记为应用主动退出,避免看门狗重启
|
||||
App.IsAppExitByUser = true;
|
||||
|
||||
// 写入退出信号文件,确保看门狗不会重启
|
||||
try
|
||||
{
|
||||
string watchdogExitSignalFile = Path.Combine(Path.GetTempPath(), "icc_watchdog_exit_" + Process.GetCurrentProcess().Id + ".flag");
|
||||
File.WriteAllText(watchdogExitSignalFile, "exit");
|
||||
LogHelper.WriteLogToFile("AutoUpdate | 已写入看门狗退出信号文件");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.WriteLogToFile($"AutoUpdate | 写入看门狗退出信号文件失败: {ex.Message}", LogHelper.LogType.Warning);
|
||||
}
|
||||
|
||||
Environment.Exit(0);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.WriteLogToFile($"AutoUpdate | 结束当前更新进程失败: {ex.Message}", LogHelper.LogType.Error);
|
||||
Environment.Exit(0);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.WriteLogToFile($"AutoUpdate | 启动更新后的应用程序失败: {ex.Message}", LogHelper.LogType.Error);
|
||||
|
||||
if (!isSilence)
|
||||
{
|
||||
MessageBox.Show($"更新完成,但启动应用程序失败:{ex.Message}\n请手动启动应用程序。", "启动失败", MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LogHelper.WriteLogToFile($"AutoUpdate | 更新后的应用程序文件不存在: {newAppPath}", LogHelper.LogType.Error);
|
||||
|
||||
if (!isSilence)
|
||||
{
|
||||
MessageBox.Show($"更新完成,但未找到应用程序文件:{newAppPath}\n请检查更新是否成功。", "文件缺失", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.WriteLogToFile($"AutoUpdate | 执行更新操作时出错: {ex.Message}", LogHelper.LogType.Error);
|
||||
|
||||
if (!isSilence)
|
||||
{
|
||||
MessageBox.Show($"更新失败:{ex.Message}", "更新失败", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 异步复制目录的辅助方法(带重试机制)
|
||||
private static async Task<bool> CopyDirectoryWithRetryAsync(string sourceDir, string destinationDir)
|
||||
{
|
||||
var dir = new DirectoryInfo(sourceDir);
|
||||
DirectoryInfo[] dirs = dir.GetDirectories();
|
||||
bool allFilesCopied = true;
|
||||
|
||||
// 如果目标目录不存在,则创建它
|
||||
if (!Directory.Exists(destinationDir))
|
||||
{
|
||||
Directory.CreateDirectory(destinationDir);
|
||||
}
|
||||
|
||||
// 复制文件
|
||||
foreach (FileInfo file in dir.GetFiles())
|
||||
{
|
||||
string targetFilePath = Path.Combine(destinationDir, file.Name);
|
||||
bool fileCopied = false;
|
||||
|
||||
// 重试机制,最多重试3次
|
||||
for (int retry = 0; retry < 3; retry++)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 如果目标文件存在,先尝试删除
|
||||
if (File.Exists(targetFilePath))
|
||||
{
|
||||
try
|
||||
{
|
||||
File.Delete(targetFilePath);
|
||||
}
|
||||
catch (IOException)
|
||||
{
|
||||
// 文件可能正在使用,等待一下再重试
|
||||
if (retry < 2)
|
||||
{
|
||||
Thread.Sleep(1000);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await Task.Run(() => file.CopyTo(targetFilePath));
|
||||
fileCopied = true;
|
||||
break;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.WriteLogToFile($"AutoUpdate | 复制文件失败 (重试 {retry + 1}/3) {file.FullName} -> {targetFilePath}: {ex.Message}", LogHelper.LogType.Warning);
|
||||
|
||||
if (retry < 2)
|
||||
{
|
||||
Thread.Sleep(1000); // 等待1秒后重试
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!fileCopied)
|
||||
{
|
||||
allFilesCopied = false;
|
||||
LogHelper.WriteLogToFile($"AutoUpdate | 文件复制最终失败: {file.FullName}", LogHelper.LogType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
// 递归复制子目录
|
||||
foreach (DirectoryInfo subDir in dirs)
|
||||
{
|
||||
string newDestinationDir = Path.Combine(destinationDir, subDir.Name);
|
||||
bool subDirCopied = await CopyDirectoryWithRetryAsync(subDir.FullName, newDestinationDir);
|
||||
if (!subDirCopied)
|
||||
{
|
||||
allFilesCopied = false;
|
||||
}
|
||||
}
|
||||
|
||||
return allFilesCopied;
|
||||
}
|
||||
|
||||
// 异步复制目录的辅助方法(原版本,保留兼容性)
|
||||
private static async Task CopyDirectoryAsync(string sourceDir, string destinationDir)
|
||||
{
|
||||
var dir = new DirectoryInfo(sourceDir);
|
||||
DirectoryInfo[] dirs = dir.GetDirectories();
|
||||
|
||||
// 如果目标目录不存在,则创建它
|
||||
if (!Directory.Exists(destinationDir))
|
||||
{
|
||||
Directory.CreateDirectory(destinationDir);
|
||||
}
|
||||
|
||||
// 复制文件
|
||||
foreach (FileInfo file in dir.GetFiles())
|
||||
{
|
||||
string targetFilePath = Path.Combine(destinationDir, file.Name);
|
||||
try
|
||||
{
|
||||
// 如果目标文件存在且正在使用,先删除
|
||||
if (File.Exists(targetFilePath))
|
||||
{
|
||||
File.Delete(targetFilePath);
|
||||
}
|
||||
|
||||
await Task.Run(() => file.CopyTo(targetFilePath));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.WriteLogToFile($"AutoUpdate | 复制文件失败 {file.FullName} -> {targetFilePath}: {ex.Message}", LogHelper.LogType.Warning);
|
||||
// 继续复制其他文件,不中断整个过程
|
||||
}
|
||||
}
|
||||
|
||||
// 递归复制子目录
|
||||
foreach (DirectoryInfo subDir in dirs)
|
||||
{
|
||||
string newDestinationDir = Path.Combine(destinationDir, subDir.Name);
|
||||
await CopyDirectoryAsync(subDir.FullName, newDestinationDir);
|
||||
}
|
||||
}
|
||||
|
||||
// 获取远程内容的通用方法
|
||||
public static async Task<string> GetRemoteContent(string fileUrl)
|
||||
{
|
||||
@@ -1450,8 +1872,8 @@ namespace Ink_Canvas.Helpers
|
||||
return false;
|
||||
}
|
||||
|
||||
// 执行安装,非静默模式
|
||||
InstallNewVersionApp(remoteVersion, false);
|
||||
// 执行安装,静默模式
|
||||
InstallNewVersionApp(remoteVersion, true);
|
||||
App.IsAppExitByUser = true;
|
||||
Application.Current.Dispatcher.Invoke(() =>
|
||||
{
|
||||
@@ -1478,6 +1900,8 @@ namespace Ink_Canvas.Helpers
|
||||
using (var client = new HttpClient())
|
||||
{
|
||||
client.DefaultRequestHeaders.Add("User-Agent", "ICC-CE Auto Updater");
|
||||
client.DefaultRequestHeaders.Add("Authorization", $"token {GitHubToken}");
|
||||
LogHelper.WriteLogToFile("AutoUpdate | 使用GitHub Token进行API调用");
|
||||
var response = await client.GetStringAsync(apiUrl);
|
||||
var arr = JArray.Parse(response);
|
||||
foreach (var item in arr)
|
||||
@@ -1515,7 +1939,7 @@ namespace Ink_Canvas.Helpers
|
||||
LogHelper.WriteLogToFile("AutoUpdate | 开始测试Windows 7 TLS连接...");
|
||||
|
||||
// 测试GitHub连接
|
||||
var testUrl = "https://bgithub.xyz/InkCanvasForClass/community/raw/refs/heads/main/AutomaticUpdateVersionControl.txt";
|
||||
var testUrl = "https://github.com/InkCanvasForClass/community/raw/refs/heads/main/AutomaticUpdateVersionControl.txt";
|
||||
|
||||
using (var handler = new HttpClientHandler())
|
||||
{
|
||||
@@ -1580,7 +2004,7 @@ namespace Ink_Canvas.Helpers
|
||||
return false;
|
||||
}
|
||||
LogHelper.WriteLogToFile($"AutoUpdate | 手动安装版本: {version}");
|
||||
InstallNewVersionApp(version, false);
|
||||
InstallNewVersionApp(version, true);
|
||||
App.IsAppExitByUser = true;
|
||||
Application.Current.Dispatcher.Invoke(() =>
|
||||
{
|
||||
@@ -1631,4 +2055,3 @@ namespace Ink_Canvas.Helpers
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace Ink_Canvas.Helpers
|
||||
private readonly Dictionary<string, HotkeyInfo> _registeredHotkeys;
|
||||
private readonly MainWindow _mainWindow;
|
||||
private bool _isDisposed = false;
|
||||
private bool _hotkeysShouldBeRegistered = false; // 启动时不注册热键,等待需要时再注册
|
||||
private bool _hotkeysShouldBeRegistered = true; // 启动时注册热键
|
||||
|
||||
// 配置文件路径
|
||||
private static readonly string HotkeyConfigFile = Path.Combine(App.RootPath, "HotkeyConfig.json");
|
||||
@@ -28,7 +28,7 @@ namespace Ink_Canvas.Helpers
|
||||
{
|
||||
_mainWindow = mainWindow ?? throw new ArgumentNullException(nameof(mainWindow));
|
||||
_registeredHotkeys = new Dictionary<string, HotkeyInfo>();
|
||||
_hotkeysShouldBeRegistered = false; // 启动时不注册热键,等待需要时再注册
|
||||
_hotkeysShouldBeRegistered = true; // 启动时注册热键
|
||||
}
|
||||
#endregion
|
||||
|
||||
@@ -288,7 +288,7 @@ namespace Ink_Canvas.Helpers
|
||||
}
|
||||
else
|
||||
{
|
||||
// 如果配置文件不存在,才使用默认快捷键
|
||||
// 如果配置文件不存在或加载失败,使用默认快捷键
|
||||
if (!File.Exists(HotkeyConfigFile))
|
||||
{
|
||||
LogHelper.WriteLogToFile("配置文件不存在,注册默认快捷键", LogHelper.LogType.Info);
|
||||
@@ -297,7 +297,9 @@ namespace Ink_Canvas.Helpers
|
||||
}
|
||||
else
|
||||
{
|
||||
LogHelper.WriteLogToFile("配置文件存在但加载失败,保持当前状态", LogHelper.LogType.Warning);
|
||||
LogHelper.WriteLogToFile("配置文件存在但加载失败,回退到默认快捷键", LogHelper.LogType.Warning);
|
||||
RegisterDefaultHotkeys();
|
||||
_hotkeysShouldBeRegistered = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -350,7 +352,9 @@ namespace Ink_Canvas.Helpers
|
||||
}
|
||||
else
|
||||
{
|
||||
LogHelper.WriteLogToFile("快捷键注册功能已经启用", LogHelper.LogType.Info);
|
||||
LogHelper.WriteLogToFile("快捷键注册功能已经启用,重新加载快捷键设置", LogHelper.LogType.Info);
|
||||
// 即使已经启用,也要重新加载快捷键设置以确保快捷键正常工作
|
||||
LoadHotkeysFromSettings();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -359,6 +363,61 @@ namespace Ink_Canvas.Helpers
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 禁用快捷键注册功能
|
||||
/// 调用此方法后,快捷键将被注销
|
||||
/// </summary>
|
||||
public void DisableHotkeyRegistration()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_hotkeysShouldBeRegistered)
|
||||
{
|
||||
_hotkeysShouldBeRegistered = false;
|
||||
LogHelper.WriteLogToFile("禁用快捷键注册功能", LogHelper.LogType.Info);
|
||||
|
||||
// 注销所有快捷键
|
||||
UnregisterAllHotkeys();
|
||||
}
|
||||
else
|
||||
{
|
||||
LogHelper.WriteLogToFile("快捷键注册功能已经禁用", LogHelper.LogType.Info);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.WriteLogToFile($"禁用快捷键注册功能时出错: {ex.Message}", LogHelper.LogType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据当前工具模式更新快捷键状态
|
||||
/// 在工具切换时调用此方法
|
||||
/// </summary>
|
||||
/// <param name="isMouseMode">是否为鼠标模式(选择模式)</param>
|
||||
public void UpdateHotkeyStateForToolMode(bool isMouseMode)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (isMouseMode)
|
||||
{
|
||||
// 鼠标模式下禁用快捷键,让键盘操作放行
|
||||
DisableHotkeyRegistration();
|
||||
LogHelper.WriteLogToFile("切换到鼠标模式,禁用快捷键以放行键盘操作", LogHelper.LogType.Info);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 非鼠标模式下启用快捷键
|
||||
EnableHotkeyRegistration();
|
||||
LogHelper.WriteLogToFile("切换到非鼠标模式,启用快捷键", LogHelper.LogType.Info);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.WriteLogToFile($"更新快捷键状态时出错: {ex.Message}", LogHelper.LogType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新快捷键配置
|
||||
/// </summary>
|
||||
@@ -752,53 +811,7 @@ namespace Ink_Canvas.Helpers
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 动态管理快捷键注册状态
|
||||
/// 根据当前工具选择状态自动注册或注销快捷键
|
||||
/// </summary>
|
||||
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
|
||||
|
||||
#region IDisposable Implementation
|
||||
@@ -806,7 +819,7 @@ namespace Ink_Canvas.Helpers
|
||||
{
|
||||
if (!_isDisposed)
|
||||
{
|
||||
UnregisterAllHotkeys();
|
||||
|
||||
_isDisposed = true;
|
||||
}
|
||||
}
|
||||
@@ -851,4 +864,4 @@ namespace Ink_Canvas.Helpers
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+16
-71
@@ -16,7 +16,6 @@
|
||||
ShowInTaskbar="False"
|
||||
Title="InkCanvasforClass"
|
||||
Topmost="True"
|
||||
KeyDown="Window_KeyDown"
|
||||
Closing="Window_Closing"
|
||||
Closed="Window_Closed"
|
||||
PreviewKeyDown="Main_Grid_PreviewKeyDown"
|
||||
@@ -43,25 +42,6 @@
|
||||
<c:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
|
||||
<c:IntNumberToString x:Key="IntNumberToString" />
|
||||
<c:IntNumberToString2 x:Key="IntNumberToString2" />
|
||||
<RoutedUICommand x:Key="KeyExit" Text=" " />
|
||||
<RoutedUICommand x:Key="HotKey_Command_Undo" Text=" " />
|
||||
<RoutedUICommand x:Key="HotKey_Command_Redo" Text=" " />
|
||||
<RoutedUICommand x:Key="HotKey_Command_Clear" Text=" " />
|
||||
<RoutedUICommand x:Key="HotKey_Capture" Text=" " />
|
||||
<RoutedUICommand x:Key="HotKey_Hide" Text=" " />
|
||||
<RoutedUICommand x:Key="HotKey_ChangeToDrawTool" Text=" " />
|
||||
<RoutedUICommand x:Key="HotKey_ChangeToQuitDrawTool" Text=" " />
|
||||
<RoutedUICommand x:Key="HotKey_ChangeToSelect" Text=" " />
|
||||
<RoutedUICommand x:Key="HotKey_ChangeToEraser" Text=" " />
|
||||
<RoutedUICommand x:Key="HotKey_ChangeToBoard" Text=" " />
|
||||
<RoutedUICommand x:Key="HotKey_ChangeToPen1" Text=" " />
|
||||
<RoutedUICommand x:Key="HotKey_ChangeToPen2" Text=" " />
|
||||
<RoutedUICommand x:Key="HotKey_ChangeToPen3" Text=" " />
|
||||
<RoutedUICommand x:Key="HotKey_ChangeToPen4" Text=" " />
|
||||
<RoutedUICommand x:Key="HotKey_ChangeToPen5" Text=" " />
|
||||
<RoutedUICommand x:Key="HotKey_DrawLine" Text=" " />
|
||||
<RoutedUICommand x:Key="HotKey_Paste" Text=" " />
|
||||
<RoutedUICommand x:Key="NothingWillHappened" Text=" " />
|
||||
|
||||
<!-- Navigation Button Style -->
|
||||
<Style x:Key="NavButton" TargetType="Button">
|
||||
@@ -130,56 +110,6 @@
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
</Window.Resources>
|
||||
<!--输入命令绑定-->
|
||||
<Window.InputBindings>
|
||||
<KeyBinding Gesture="Escape" Command="{StaticResource KeyExit}" />
|
||||
<KeyBinding Modifiers="Control" Key="Z" Command="{StaticResource HotKey_Command_Undo}" />
|
||||
<KeyBinding Modifiers="Control" Key="Y" Command="{StaticResource HotKey_Command_Redo}" />
|
||||
<KeyBinding Modifiers="Control" Key="E" Command="{StaticResource HotKey_Command_Clear}" />
|
||||
<KeyBinding Modifiers="Alt" Key="C" Command="{StaticResource HotKey_Capture}" />
|
||||
<KeyBinding Modifiers="Alt" Key="V" Command="{StaticResource HotKey_Hide}" />
|
||||
<KeyBinding Modifiers="Alt" Key="S" Command="{StaticResource HotKey_ChangeToSelect}" />
|
||||
<KeyBinding Modifiers="Alt" Key="D" Command="{StaticResource HotKey_ChangeToDrawTool}" />
|
||||
<KeyBinding Modifiers="Alt" Key="Q" Command="{StaticResource HotKey_ChangeToQuitDrawTool}" />
|
||||
<KeyBinding Modifiers="Alt" Key="E" Command="{StaticResource HotKey_ChangeToEraser}" />
|
||||
<KeyBinding Modifiers="Alt" Key="B" Command="{StaticResource HotKey_ChangeToBoard}" />
|
||||
<KeyBinding Modifiers="Alt" Key="D1" Command="{StaticResource HotKey_ChangeToPen1}" />
|
||||
<KeyBinding Modifiers="Alt" Key="D2" Command="{StaticResource HotKey_ChangeToPen2}" />
|
||||
<KeyBinding Modifiers="Alt" Key="D3" Command="{StaticResource HotKey_ChangeToPen3}" />
|
||||
<KeyBinding Modifiers="Alt" Key="D4" Command="{StaticResource HotKey_ChangeToPen4}" />
|
||||
<KeyBinding Modifiers="Alt" Key="D5" Command="{StaticResource HotKey_ChangeToPen5}" />
|
||||
<KeyBinding Modifiers="Alt" Key="L" Command="{StaticResource HotKey_DrawLine}" />
|
||||
<KeyBinding Modifiers="Control" Key="V" Command="{StaticResource HotKey_Paste}" />
|
||||
<KeyBinding Modifiers="Alt" Key="F4" Command="{StaticResource NothingWillHappened}" />
|
||||
</Window.InputBindings>
|
||||
<!--命令执行方法绑定-->
|
||||
<Window.CommandBindings>
|
||||
<CommandBinding CanExecute="CommandBinding_CanExecute" Command="{StaticResource KeyExit}" Executed="KeyExit" />
|
||||
<CommandBinding CanExecute="CommandBinding_CanExecute" Command="{StaticResource HotKey_Command_Undo}"
|
||||
Executed="HotKey_Undo" />
|
||||
<CommandBinding CanExecute="CommandBinding_CanExecute" Command="{StaticResource HotKey_Command_Redo}"
|
||||
Executed="HotKey_Redo" />
|
||||
<CommandBinding CanExecute="CommandBinding_CanExecute" Command="{StaticResource HotKey_Command_Clear}"
|
||||
Executed="HotKey_Clear" />
|
||||
<CommandBinding CanExecute="CommandBinding_CanExecute" Command="{StaticResource HotKey_ChangeToDrawTool}"
|
||||
Executed="KeyChangeToDrawTool" />
|
||||
<CommandBinding CanExecute="CommandBinding_CanExecute" Command="{StaticResource HotKey_ChangeToQuitDrawTool}"
|
||||
Executed="KeyChangeToQuitDrawTool" />
|
||||
<CommandBinding CanExecute="CommandBinding_CanExecute" Command="{StaticResource HotKey_ChangeToSelect}"
|
||||
Executed="KeyChangeToSelect" />
|
||||
<CommandBinding CanExecute="CommandBinding_CanExecute" Command="{StaticResource HotKey_ChangeToEraser}"
|
||||
Executed="KeyChangeToEraser" />
|
||||
<CommandBinding CanExecute="CommandBinding_CanExecute" Command="{StaticResource HotKey_ChangeToBoard}"
|
||||
Executed="KeyChangeToBoard" />
|
||||
<CommandBinding CanExecute="CommandBinding_CanExecute" Command="{StaticResource HotKey_Capture}"
|
||||
Executed="KeyCapture" />
|
||||
<CommandBinding CanExecute="CommandBinding_CanExecute" Command="{StaticResource HotKey_Hide}"
|
||||
Executed="KeyHide" />
|
||||
<CommandBinding CanExecute="CommandBinding_CanExecute" Command="{StaticResource HotKey_DrawLine}"
|
||||
Executed="KeyDrawLine" />
|
||||
<CommandBinding CanExecute="CommandBinding_CanExecute" Command="{StaticResource HotKey_Paste}"
|
||||
Executed="HandleGlobalPaste" />
|
||||
</Window.CommandBindings>
|
||||
|
||||
<Grid x:Name="Main_Grid">
|
||||
|
||||
@@ -911,7 +841,20 @@
|
||||
IsOn="False" FontFamily="Microsoft YaHei UI" FontWeight="Bold"
|
||||
Toggled="ToggleSwitchEnablePalmEraser_Toggled" />
|
||||
</ui:SimpleStackPanel>
|
||||
<TextBlock Text="# 开启后,两个及以上触点且触摸面积较大时自动切换为橡皮擦,抬手后恢复原编辑模式。" TextWrapping="Wrap" Foreground="#a1a1aa" />
|
||||
<TextBlock Text="# 开启后,两个及以上触点且触摸面积较大时自动切换为橡皮擦,抬手后恢复原编辑模式。" TextWrapping="Wrap" Foreground="#a1a1aa" />
|
||||
<ui:SimpleStackPanel Orientation="Horizontal" HorizontalAlignment="Left"
|
||||
Visibility="{Binding ElementName=ToggleSwitchEnablePalmEraser, Path=IsOn, Converter={StaticResource BooleanToVisibilityConverter}}">
|
||||
<TextBlock Foreground="#fafafa" Text="手掌擦敏感度" VerticalAlignment="Center"
|
||||
FontSize="14" Margin="0,0,16,0" />
|
||||
<ComboBox Name="ComboBoxPalmEraserSensitivity" Width="120" SelectionChanged="ComboBoxPalmEraserSensitivity_SelectionChanged">
|
||||
<ComboBoxItem Content="低敏感度" />
|
||||
<ComboBoxItem Content="中敏感度" />
|
||||
<ComboBoxItem Content="高敏感度" />
|
||||
</ComboBox>
|
||||
</ui:SimpleStackPanel>
|
||||
<TextBlock Text="# 低敏感度:需要更大的触摸面积和更多触摸点,减少误判;高敏感度:更容易触发手掌擦,但可能误判手指。"
|
||||
TextWrapping="Wrap" Foreground="#a1a1aa"
|
||||
Visibility="{Binding ElementName=ToggleSwitchEnablePalmEraser, Path=IsOn, Converter={StaticResource BooleanToVisibilityConverter}}" />
|
||||
</ui:SimpleStackPanel>
|
||||
</GroupBox>
|
||||
<GroupBox Name="GroupBoxInkRecognition">
|
||||
@@ -5684,6 +5627,7 @@
|
||||
<ui:SimpleStackPanel Margin="0,0,0,0" Height="40" Spacing="0"
|
||||
Orientation="Horizontal">
|
||||
<ui:SimpleStackPanel MouseDown="Border_MouseDown"
|
||||
MouseUp="SymbolIconScreenshot_MouseUp"
|
||||
Margin="0,0,0,0" Height="38" Width="32"
|
||||
Orientation="Vertical">
|
||||
<Image Margin="0,4,0,2" Height="19" Width="19">
|
||||
@@ -8676,6 +8620,7 @@
|
||||
<ui:SimpleStackPanel Margin="0,0,0,0" Height="40" Spacing="0"
|
||||
Orientation="Horizontal">
|
||||
<ui:SimpleStackPanel MouseDown="Border_MouseDown"
|
||||
MouseUp="SymbolIconScreenshot_MouseUp"
|
||||
Margin="0,0,0,0" Height="38" Width="32"
|
||||
Orientation="Vertical">
|
||||
<Image Margin="0,4,0,2" Height="19" Width="19">
|
||||
|
||||
@@ -239,6 +239,9 @@ namespace Ink_Canvas
|
||||
// 添加窗口激活事件处理,确保置顶状态在窗口重新激活时得到保持
|
||||
this.Activated += Window_Activated;
|
||||
this.Deactivated += Window_Deactivated;
|
||||
|
||||
// 为浮动栏按钮添加触摸事件支持
|
||||
AddTouchSupportToFloatingBarButtons();
|
||||
}
|
||||
|
||||
|
||||
@@ -274,7 +277,6 @@ namespace Ink_Canvas
|
||||
drawingAttributes.FitToCurve = Settings.Canvas.FitToCurve;
|
||||
}
|
||||
|
||||
inkCanvas.EditingMode = InkCanvasEditingMode.Ink;
|
||||
inkCanvas.Gesture += InkCanvas_Gesture;
|
||||
}
|
||||
catch { }
|
||||
@@ -808,6 +810,7 @@ namespace Ink_Canvas
|
||||
|
||||
// 创建并显示更新窗口
|
||||
HasNewUpdateWindow updateWindow = new HasNewUpdateWindow(currentVersion, AvailableLatestVersion, releaseDate, releaseNotes);
|
||||
updateWindow.Owner = this;
|
||||
bool? dialogResult = updateWindow.ShowDialog();
|
||||
|
||||
// 如果窗口被关闭但没有点击按钮,则不执行任何操作
|
||||
@@ -844,7 +847,7 @@ namespace Ink_Canvas
|
||||
App.IsAppExitByUser = true;
|
||||
|
||||
// 准备批处理脚本
|
||||
AutoUpdateHelper.InstallNewVersionApp(AvailableLatestVersion, false);
|
||||
AutoUpdateHelper.InstallNewVersionApp(AvailableLatestVersion, true); // 修改为静默模式,避免重复启动进程
|
||||
|
||||
// 关闭软件,让安装程序接管
|
||||
Application.Current.Shutdown();
|
||||
@@ -1676,6 +1679,8 @@ namespace Ink_Canvas
|
||||
private static extern bool SetForegroundWindow(IntPtr hWnd);
|
||||
[DllImport("user32.dll")]
|
||||
private static extern bool PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
|
||||
[DllImport("kernel32.dll")]
|
||||
private static extern uint GetCurrentProcessId();
|
||||
|
||||
|
||||
private const int GWL_EXSTYLE = -20;
|
||||
@@ -1818,11 +1823,21 @@ namespace Ink_Canvas
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查当前窗口是否在最顶层
|
||||
// 检查是否有子窗口打开(模态对话框)
|
||||
var foregroundWindow = GetForegroundWindow();
|
||||
if (foregroundWindow != hwnd)
|
||||
{
|
||||
// 如果窗口不在最顶层,重新设置置顶
|
||||
// 检查前景窗口是否是当前应用程序的子窗口
|
||||
var foregroundWindowProcessId = GetWindowThreadProcessId(foregroundWindow, out uint processId);
|
||||
var currentProcessId = GetCurrentProcessId();
|
||||
|
||||
if (processId == currentProcessId)
|
||||
{
|
||||
// 如果有子窗口在前景,暂停置顶维护
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果窗口不在最顶层且没有子窗口,重新设置置顶
|
||||
SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0,
|
||||
SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_SHOWWINDOW | SWP_NOOWNERZORDER);
|
||||
|
||||
@@ -1832,7 +1847,6 @@ namespace Ink_Canvas
|
||||
{
|
||||
SetWindowLong(hwnd, GWL_EXSTYLE, exStyle | WS_EX_TOPMOST);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -2025,8 +2039,11 @@ namespace Ink_Canvas
|
||||
try
|
||||
{
|
||||
_globalHotkeyManager = new GlobalHotkeyManager(this);
|
||||
// 不在这里加载快捷键,等待需要时再加载
|
||||
LogHelper.WriteLogToFile("全局快捷键管理器已初始化(未加载快捷键)", LogHelper.LogType.Event);
|
||||
// 启动时加载快捷键,但默认为鼠标模式,禁用快捷键以放行键盘操作
|
||||
_globalHotkeyManager.EnableHotkeyRegistration();
|
||||
// 启动时默认为鼠标模式,禁用快捷键
|
||||
_globalHotkeyManager.UpdateHotkeyStateForToolMode(true);
|
||||
LogHelper.WriteLogToFile("全局快捷键管理器已初始化,启动时默认为鼠标模式并禁用快捷键", LogHelper.LogType.Event);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -2047,6 +2064,7 @@ namespace Ink_Canvas
|
||||
return;
|
||||
}
|
||||
var hotkeySettingsWindow = new HotkeySettingsWindow(this, _globalHotkeyManager);
|
||||
hotkeySettingsWindow.Owner = this;
|
||||
hotkeySettingsWindow.ShowDialog();
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -2179,5 +2197,38 @@ namespace Ink_Canvas
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// 集中管理工具模式切换和快捷键状态更新
|
||||
/// 避免在每个工具按钮点击时重复刷新快捷键状态
|
||||
/// </summary>
|
||||
/// <param name="newMode">新的编辑模式</param>
|
||||
/// <param name="additionalActions">可选的额外操作委托</param>
|
||||
internal void SetCurrentToolMode(InkCanvasEditingMode newMode, Action additionalActions = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 执行模式切换
|
||||
inkCanvas.EditingMode = newMode;
|
||||
|
||||
// 根据模式确定是否为鼠标模式(无工具模式)
|
||||
bool isMouseMode = newMode == InkCanvasEditingMode.None;
|
||||
|
||||
// 更新快捷键状态
|
||||
if (_globalHotkeyManager != null)
|
||||
{
|
||||
_globalHotkeyManager.UpdateHotkeyStateForToolMode(isMouseMode);
|
||||
}
|
||||
|
||||
// 执行额外的操作(如果有)
|
||||
additionalActions?.Invoke();
|
||||
|
||||
LogHelper.WriteLogToFile($"工具模式已切换到: {newMode}, 鼠标模式: {isMouseMode}", LogHelper.LogType.Trace);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.WriteLogToFile($"设置工具模式时出错: {ex.Message}", LogHelper.LogType.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -704,7 +704,8 @@ namespace Ink_Canvas
|
||||
forceEraser = false;
|
||||
forcePointEraser = false;
|
||||
drawingShapeMode = 0;
|
||||
inkCanvas.EditingMode = InkCanvasEditingMode.Select;
|
||||
// 使用集中化的工具模式切换方法
|
||||
SetCurrentToolMode(InkCanvasEditingMode.Select);
|
||||
SetCursorBasedOnEditingMode(inkCanvas);
|
||||
}
|
||||
|
||||
@@ -721,7 +722,8 @@ namespace Ink_Canvas
|
||||
forcePointEraser = false;
|
||||
|
||||
inkCanvas.EraserShape = new EllipseStylusShape(5, 5);
|
||||
inkCanvas.EditingMode = InkCanvasEditingMode.EraseByStroke;
|
||||
// 使用集中化的工具模式切换方法
|
||||
SetCurrentToolMode(InkCanvasEditingMode.EraseByStroke);
|
||||
drawingShapeMode = 0;
|
||||
|
||||
// 修复:切换到线擦时,确保重置笔的状态
|
||||
|
||||
@@ -64,7 +64,8 @@ namespace Ink_Canvas
|
||||
{
|
||||
inkCanvas.IsManipulationEnabled = true;
|
||||
drawingShapeMode = 0;
|
||||
inkCanvas.EditingMode = InkCanvasEditingMode.Ink;
|
||||
// 使用集中化的工具模式切换方法
|
||||
SetCurrentToolMode(InkCanvasEditingMode.Ink);
|
||||
CancelSingleFingerDragMode();
|
||||
CheckColorTheme();
|
||||
}
|
||||
|
||||
@@ -28,35 +28,6 @@ namespace Ink_Canvas
|
||||
{
|
||||
public partial class MainWindow : Window
|
||||
{
|
||||
#region 快捷键状态管理
|
||||
|
||||
/// <summary>
|
||||
/// 统一的快捷键状态刷新方法
|
||||
/// 在工具切换时调用,避免重复代码
|
||||
/// </summary>
|
||||
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 "手勢"按鈕
|
||||
|
||||
@@ -820,8 +791,6 @@ namespace Ink_Canvas
|
||||
BtnSelect_Click(null, null);
|
||||
HideSubPanels("select");
|
||||
|
||||
// 工具切换完成后,统一刷新快捷键状态
|
||||
RefreshHotkeyState();
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -915,7 +884,11 @@ namespace Ink_Canvas
|
||||
HideSubPanels();
|
||||
BtnSettings_Click(null, null);
|
||||
}
|
||||
|
||||
private async void SymbolIconScreenshot_MouseUp(object sender, MouseButtonEventArgs e) {
|
||||
HideSubPanelsImmediately();
|
||||
await Task.Delay(50);
|
||||
SaveScreenShotToDesktop();
|
||||
}
|
||||
|
||||
private void ImageCountdownTimer_MouseUp(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
@@ -1589,6 +1562,10 @@ namespace Ink_Canvas
|
||||
// 隱藏高亮
|
||||
HideFloatingBarHighlight();
|
||||
|
||||
// 使用集中化的工具模式切换方法,确保快捷键状态正确更新
|
||||
// 鼠标模式下应该禁用快捷键以放行键盘操作
|
||||
SetCurrentToolMode(InkCanvasEditingMode.None);
|
||||
|
||||
// 切换前自动截图保存墨迹
|
||||
if (inkCanvas.Strokes.Count > 0 &&
|
||||
inkCanvas.Strokes.Count > Settings.Automation.MinimumAutomationStrokeNumber)
|
||||
@@ -1681,14 +1658,6 @@ 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)
|
||||
@@ -1719,7 +1688,8 @@ namespace Ink_Canvas
|
||||
|
||||
if (Pen_Icon.Background == null || StackPanelCanvasControls.Visibility == Visibility.Collapsed)
|
||||
{
|
||||
inkCanvas.EditingMode = InkCanvasEditingMode.Ink;
|
||||
// 使用集中化的工具模式切换方法
|
||||
SetCurrentToolMode(InkCanvasEditingMode.Ink);
|
||||
|
||||
GridTransparencyFakeBackground.Opacity = 1;
|
||||
GridTransparencyFakeBackground.Background = new SolidColorBrush(StringToColor("#01FFFFFF"));
|
||||
@@ -1752,7 +1722,8 @@ namespace Ink_Canvas
|
||||
StackPanelCanvasControls.Visibility = Visibility.Visible;
|
||||
//AnimationsHelper.ShowWithSlideFromLeftAndFade(StackPanelCanvasControls);
|
||||
CheckEnableTwoFingerGestureBtnVisibility(true);
|
||||
inkCanvas.EditingMode = InkCanvasEditingMode.Ink;
|
||||
// 使用集中化的工具模式切换方法
|
||||
SetCurrentToolMode(InkCanvasEditingMode.Ink);
|
||||
|
||||
// 在批注模式下显示快捷调色盘(如果设置中启用了)
|
||||
if (Settings.Appearance.IsShowQuickColorPalette && QuickColorPalettePanel != null && QuickColorPaletteSingleRowPanel != null)
|
||||
@@ -1873,7 +1844,8 @@ namespace Ink_Canvas
|
||||
{
|
||||
SaveStrokes();
|
||||
}
|
||||
inkCanvas.EditingMode = InkCanvasEditingMode.Ink;
|
||||
// 使用集中化的工具模式切换方法
|
||||
SetCurrentToolMode(InkCanvasEditingMode.Ink);
|
||||
|
||||
// 修复:从线擦切换到批注时,保持之前的笔类型状态
|
||||
forceEraser = false;
|
||||
@@ -1901,9 +1873,6 @@ namespace Ink_Canvas
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 延迟半秒后再刷新快捷键状态
|
||||
Task.Delay(500).ContinueWith(_ => Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() => RefreshHotkeyState())));
|
||||
|
||||
// 修复:从线擦切换到批注时,保持之前的笔类型状态
|
||||
forceEraser = false;
|
||||
@@ -1936,7 +1905,8 @@ namespace Ink_Canvas
|
||||
EnableAdvancedEraserSystem();
|
||||
|
||||
// 使用新的高级橡皮擦系统
|
||||
inkCanvas.EditingMode = InkCanvasEditingMode.EraseByPoint;
|
||||
// 使用集中化的工具模式切换方法
|
||||
SetCurrentToolMode(InkCanvasEditingMode.EraseByPoint);
|
||||
ApplyAdvancedEraserShape(); // 使用新的橡皮擦形状应用方法
|
||||
SetCursorBasedOnEditingMode(inkCanvas);
|
||||
HideSubPanels("eraser"); // 高亮橡皮按钮
|
||||
@@ -1961,9 +1931,6 @@ namespace Ink_Canvas
|
||||
AnimationsHelper.HideWithSlideAndFade(BoardEraserSizePanel);
|
||||
}
|
||||
}
|
||||
|
||||
// 工具切换完成后,统一刷新快捷键状态
|
||||
RefreshHotkeyState();
|
||||
}
|
||||
|
||||
private void BoardEraserIcon_Click(object sender, RoutedEventArgs e)
|
||||
@@ -1978,7 +1945,8 @@ namespace Ink_Canvas
|
||||
EnableAdvancedEraserSystem();
|
||||
|
||||
// 使用新的高级橡皮擦系统
|
||||
inkCanvas.EditingMode = InkCanvasEditingMode.EraseByPoint;
|
||||
// 使用集中化的工具模式切换方法
|
||||
SetCurrentToolMode(InkCanvasEditingMode.EraseByPoint);
|
||||
ApplyAdvancedEraserShape(); // 使用新的橡皮擦形状应用方法
|
||||
SetCursorBasedOnEditingMode(inkCanvas);
|
||||
HideSubPanels("eraser"); // 高亮橡皮按钮
|
||||
@@ -1998,9 +1966,6 @@ namespace Ink_Canvas
|
||||
AnimationsHelper.HideWithSlideAndFade(EraserSizePanel);
|
||||
}
|
||||
}
|
||||
|
||||
// 工具切换完成后,统一刷新快捷键状态
|
||||
RefreshHotkeyState();
|
||||
}
|
||||
|
||||
private void EraserIconByStrokes_Click(object sender, RoutedEventArgs e)
|
||||
@@ -2018,7 +1983,8 @@ namespace Ink_Canvas
|
||||
forcePointEraser = false;
|
||||
|
||||
inkCanvas.EraserShape = new EllipseStylusShape(5, 5);
|
||||
inkCanvas.EditingMode = InkCanvasEditingMode.EraseByStroke;
|
||||
// 使用集中化的工具模式切换方法
|
||||
SetCurrentToolMode(InkCanvasEditingMode.EraseByStroke);
|
||||
drawingShapeMode = 0;
|
||||
|
||||
// 修复:切换到线擦时,保存当前的笔类型状态,而不是强制重置
|
||||
@@ -2030,8 +1996,6 @@ namespace Ink_Canvas
|
||||
|
||||
HideSubPanels("eraserByStrokes");
|
||||
|
||||
// 工具切换完成后,统一刷新快捷键状态
|
||||
RefreshHotkeyState();
|
||||
}
|
||||
|
||||
private void CursorWithDelIcon_Click(object sender, RoutedEventArgs e)
|
||||
@@ -2301,7 +2265,8 @@ namespace Ink_Canvas
|
||||
}
|
||||
else
|
||||
{
|
||||
inkCanvas.EditingMode = InkCanvasEditingMode.Select;
|
||||
// 使用集中化的工具模式切换方法
|
||||
SetCurrentToolMode(InkCanvasEditingMode.Select);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3109,6 +3074,158 @@ namespace Ink_Canvas
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 触摸事件支持
|
||||
|
||||
/// <summary>
|
||||
/// 为浮动栏按钮添加触摸和手写笔事件支持,让触摸和手写笔点击直接调用对应的鼠标点击方法
|
||||
/// </summary>
|
||||
private void AddTouchSupportToFloatingBarButtons()
|
||||
{
|
||||
// 为主要的浮动栏按钮添加触摸和手写笔事件支持
|
||||
if (SymbolIconSelect != null)
|
||||
{
|
||||
SymbolIconSelect.TouchDown += (s, e) => SymbolIconSelect_MouseUp(s, null);
|
||||
SymbolIconSelect.StylusDown += (s, e) => SymbolIconSelect_MouseUp(s, null);
|
||||
}
|
||||
|
||||
if (SymbolIconUndo != null)
|
||||
{
|
||||
SymbolIconUndo.TouchDown += (s, e) => SymbolIconUndo_MouseUp(s, null);
|
||||
SymbolIconUndo.StylusDown += (s, e) => SymbolIconUndo_MouseUp(s, null);
|
||||
}
|
||||
|
||||
if (SymbolIconRedo != null)
|
||||
{
|
||||
SymbolIconRedo.TouchDown += (s, e) => SymbolIconRedo_MouseUp(s, null);
|
||||
SymbolIconRedo.StylusDown += (s, e) => SymbolIconRedo_MouseUp(s, null);
|
||||
}
|
||||
|
||||
if (SymbolIconDelete != null)
|
||||
{
|
||||
SymbolIconDelete.TouchDown += (s, e) => SymbolIconDelete_MouseUp(s, null);
|
||||
SymbolIconDelete.StylusDown += (s, e) => SymbolIconDelete_MouseUp(s, null);
|
||||
}
|
||||
|
||||
if (ToolsFloatingBarBtn != null)
|
||||
{
|
||||
ToolsFloatingBarBtn.TouchDown += (s, e) => SymbolIconTools_MouseUp(s, null);
|
||||
ToolsFloatingBarBtn.StylusDown += (s, e) => SymbolIconTools_MouseUp(s, null);
|
||||
}
|
||||
|
||||
if (RandomDrawPanel != null)
|
||||
{
|
||||
RandomDrawPanel.TouchDown += (s, e) => SymbolIconRand_MouseUp(s, null);
|
||||
RandomDrawPanel.StylusDown += (s, e) => SymbolIconRand_MouseUp(s, null);
|
||||
}
|
||||
|
||||
if (SingleDrawPanel != null)
|
||||
{
|
||||
SingleDrawPanel.TouchDown += (s, e) => SymbolIconRandOne_MouseUp(s, null);
|
||||
SingleDrawPanel.StylusDown += (s, e) => SymbolIconRandOne_MouseUp(s, null);
|
||||
}
|
||||
|
||||
// 注意:Screenshot和Settings按钮在XAML中没有直接的Name属性,需要通过其他方式绑定
|
||||
// 这些按钮的事件处理已经在XAML中通过MouseUp绑定
|
||||
|
||||
if (BorderFloatingBarMoveControls != null)
|
||||
{
|
||||
BorderFloatingBarMoveControls.TouchDown += (s, e) => SymbolIconEmoji_MouseUp(s, null);
|
||||
BorderFloatingBarMoveControls.StylusDown += (s, e) => SymbolIconEmoji_MouseUp(s, null);
|
||||
}
|
||||
|
||||
// 白板模式下的按钮不添加触摸事件支持,保持原有的鼠标事件处理
|
||||
|
||||
// 为快捷调色盘按钮添加触摸和手写笔事件支持
|
||||
if (QuickColorWhite != null)
|
||||
{
|
||||
QuickColorWhite.TouchDown += (s, e) => QuickColorWhite_Click(s, null);
|
||||
QuickColorWhite.StylusDown += (s, e) => QuickColorWhite_Click(s, null);
|
||||
}
|
||||
|
||||
if (QuickColorOrange != null)
|
||||
{
|
||||
QuickColorOrange.TouchDown += (s, e) => QuickColorOrange_Click(s, null);
|
||||
QuickColorOrange.StylusDown += (s, e) => QuickColorOrange_Click(s, null);
|
||||
}
|
||||
|
||||
if (QuickColorYellow != null)
|
||||
{
|
||||
QuickColorYellow.TouchDown += (s, e) => QuickColorYellow_Click(s, null);
|
||||
QuickColorYellow.StylusDown += (s, e) => QuickColorYellow_Click(s, null);
|
||||
}
|
||||
|
||||
if (QuickColorBlack != null)
|
||||
{
|
||||
QuickColorBlack.TouchDown += (s, e) => QuickColorBlack_Click(s, null);
|
||||
QuickColorBlack.StylusDown += (s, e) => QuickColorBlack_Click(s, null);
|
||||
}
|
||||
|
||||
if (QuickColorBlue != null)
|
||||
{
|
||||
QuickColorBlue.TouchDown += (s, e) => QuickColorBlue_Click(s, null);
|
||||
QuickColorBlue.StylusDown += (s, e) => QuickColorBlue_Click(s, null);
|
||||
}
|
||||
|
||||
if (QuickColorRed != null)
|
||||
{
|
||||
QuickColorRed.TouchDown += (s, e) => QuickColorRed_Click(s, null);
|
||||
QuickColorRed.StylusDown += (s, e) => QuickColorRed_Click(s, null);
|
||||
}
|
||||
|
||||
if (QuickColorGreen != null)
|
||||
{
|
||||
QuickColorGreen.TouchDown += (s, e) => QuickColorGreen_Click(s, null);
|
||||
QuickColorGreen.StylusDown += (s, e) => QuickColorGreen_Click(s, null);
|
||||
}
|
||||
|
||||
if (QuickColorPurple != null)
|
||||
{
|
||||
QuickColorPurple.TouchDown += (s, e) => QuickColorPurple_Click(s, null);
|
||||
QuickColorPurple.StylusDown += (s, e) => QuickColorPurple_Click(s, null);
|
||||
}
|
||||
|
||||
// 单行快捷调色盘
|
||||
if (QuickColorWhiteSingle != null)
|
||||
{
|
||||
QuickColorWhiteSingle.TouchDown += (s, e) => QuickColorWhite_Click(s, null);
|
||||
QuickColorWhiteSingle.StylusDown += (s, e) => QuickColorWhite_Click(s, null);
|
||||
}
|
||||
|
||||
if (QuickColorOrangeSingle != null)
|
||||
{
|
||||
QuickColorOrangeSingle.TouchDown += (s, e) => QuickColorOrange_Click(s, null);
|
||||
QuickColorOrangeSingle.StylusDown += (s, e) => QuickColorOrange_Click(s, null);
|
||||
}
|
||||
|
||||
if (QuickColorYellowSingle != null)
|
||||
{
|
||||
QuickColorYellowSingle.TouchDown += (s, e) => QuickColorYellow_Click(s, null);
|
||||
QuickColorYellowSingle.StylusDown += (s, e) => QuickColorYellow_Click(s, null);
|
||||
}
|
||||
|
||||
if (QuickColorBlackSingle != null)
|
||||
{
|
||||
QuickColorBlackSingle.TouchDown += (s, e) => QuickColorBlack_Click(s, null);
|
||||
QuickColorBlackSingle.StylusDown += (s, e) => QuickColorBlack_Click(s, null);
|
||||
}
|
||||
|
||||
if (QuickColorRedSingle != null)
|
||||
{
|
||||
QuickColorRedSingle.TouchDown += (s, e) => QuickColorRed_Click(s, null);
|
||||
QuickColorRedSingle.StylusDown += (s, e) => QuickColorRed_Click(s, null);
|
||||
}
|
||||
|
||||
if (QuickColorGreenSingle != null)
|
||||
{
|
||||
QuickColorGreenSingle.TouchDown += (s, e) => QuickColorGreen_Click(s, null);
|
||||
QuickColorGreenSingle.StylusDown += (s, e) => QuickColorGreen_Click(s, null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
|
||||
@@ -44,15 +44,8 @@ namespace Ink_Canvas
|
||||
}
|
||||
}
|
||||
|
||||
private void Window_KeyDown(object sender, KeyEventArgs e)
|
||||
{
|
||||
if (e.Key == Key.Escape) KeyExit(null, null);
|
||||
}
|
||||
|
||||
private void CommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
|
||||
{
|
||||
e.CanExecute = true;
|
||||
}
|
||||
// 保留PPT翻页快捷键处理
|
||||
// 以下方法保留供全局快捷键调用
|
||||
|
||||
private void HotKey_Undo(object sender, ExecutedRoutedEventArgs e)
|
||||
{
|
||||
|
||||
@@ -276,8 +276,10 @@ namespace Ink_Canvas
|
||||
{
|
||||
if (inkCanvas.GetSelectedStrokes().Count == inkCanvas.Strokes.Count)
|
||||
{
|
||||
inkCanvas.EditingMode = InkCanvasEditingMode.Ink;
|
||||
inkCanvas.EditingMode = InkCanvasEditingMode.Select;
|
||||
// 使用集中化的工具模式切换方法
|
||||
SetCurrentToolMode(InkCanvasEditingMode.Ink, () => {
|
||||
SetCurrentToolMode(InkCanvasEditingMode.Select);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -290,7 +292,8 @@ namespace Ink_Canvas
|
||||
}
|
||||
else
|
||||
{
|
||||
inkCanvas.EditingMode = InkCanvasEditingMode.Select;
|
||||
// 使用集中化的工具模式切换方法
|
||||
SetCurrentToolMode(InkCanvasEditingMode.Select);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -454,7 +457,8 @@ namespace Ink_Canvas
|
||||
else
|
||||
{
|
||||
// 新增:启动套索选择模式
|
||||
inkCanvas.EditingMode = InkCanvasEditingMode.Select;
|
||||
// 使用集中化的工具模式切换方法
|
||||
SetCurrentToolMode(InkCanvasEditingMode.Select);
|
||||
inkCanvas.Select(new StrokeCollection());
|
||||
}
|
||||
}
|
||||
@@ -492,7 +496,8 @@ namespace Ink_Canvas
|
||||
forceEraser = false;
|
||||
forcePointEraser = false;
|
||||
drawingShapeMode = 0;
|
||||
inkCanvas.EditingMode = InkCanvasEditingMode.Select;
|
||||
// 使用集中化的工具模式切换方法
|
||||
SetCurrentToolMode(InkCanvasEditingMode.Select);
|
||||
SetCursorBasedOnEditingMode(inkCanvas);
|
||||
}
|
||||
|
||||
@@ -502,7 +507,8 @@ namespace Ink_Canvas
|
||||
forceEraser = false;
|
||||
forcePointEraser = false;
|
||||
drawingShapeMode = 0;
|
||||
inkCanvas.EditingMode = InkCanvasEditingMode.Select;
|
||||
// 使用集中化的工具模式切换方法
|
||||
SetCurrentToolMode(InkCanvasEditingMode.Select);
|
||||
inkCanvas.IsManipulationEnabled = true;
|
||||
SetCursorBasedOnEditingMode(inkCanvas);
|
||||
}
|
||||
|
||||
@@ -3034,6 +3034,12 @@ namespace Ink_Canvas
|
||||
|
||||
#endregion
|
||||
|
||||
private void ComboBoxPalmEraserSensitivity_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
if (!isLoaded) return;
|
||||
Settings.Canvas.PalmEraserSensitivity = ComboBoxPalmEraserSensitivity.SelectedIndex;
|
||||
SaveSettingsToFile();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -683,6 +683,7 @@ namespace Ink_Canvas
|
||||
if (Settings.Canvas != null)
|
||||
{
|
||||
ToggleSwitchEnablePalmEraser.IsOn = Settings.Canvas.EnablePalmEraser;
|
||||
ComboBoxPalmEraserSensitivity.SelectedIndex = Settings.Canvas.PalmEraserSensitivity;
|
||||
}
|
||||
|
||||
// Advanced
|
||||
|
||||
@@ -555,6 +555,7 @@ namespace Ink_Canvas
|
||||
{
|
||||
// 禁用原有的FitToCurve,使用新的高级贝塞尔曲线平滑
|
||||
if (Settings.Canvas.FitToCurve) drawingAttributes.FitToCurve = false;
|
||||
// 在绘制过程中禁用浮动栏交互,避免干扰绘制
|
||||
ViewboxFloatingBar.IsHitTestVisible = false;
|
||||
BlackboardUIGridForInkReplay.IsHitTestVisible = false;
|
||||
List<Point> pointList;
|
||||
@@ -1668,6 +1669,18 @@ namespace Ink_Canvas
|
||||
|
||||
private void inkCanvas_MouseDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
// 检查鼠标点击是否发生在浮动栏区域,如果是则允许事件传播到浮动栏按钮
|
||||
var mousePoint = e.GetPosition(this);
|
||||
var floatingBarBounds = ViewboxFloatingBar.TransformToAncestor(this).TransformBounds(
|
||||
new Rect(0, 0, ViewboxFloatingBar.ActualWidth, ViewboxFloatingBar.ActualHeight));
|
||||
|
||||
// 如果鼠标点击发生在浮动栏区域,不阻止事件传播,让浮动栏按钮能够接收鼠标事件
|
||||
if (floatingBarBounds.Contains(mousePoint))
|
||||
{
|
||||
// 不设置 ViewboxFloatingBar.IsHitTestVisible = false,让浮动栏按钮能够接收鼠标事件
|
||||
return;
|
||||
}
|
||||
|
||||
inkCanvas.CaptureMouse();
|
||||
ViewboxFloatingBar.IsHitTestVisible = false;
|
||||
BlackboardUIGridForInkReplay.IsHitTestVisible = false;
|
||||
|
||||
@@ -109,6 +109,18 @@ namespace Ink_Canvas
|
||||
|
||||
private void MainWindow_TouchDown(object sender, TouchEventArgs e)
|
||||
{
|
||||
// 检查触摸是否发生在浮动栏区域,如果是则允许事件传播到浮动栏按钮
|
||||
var touchPoint = e.GetTouchPoint(this);
|
||||
var floatingBarBounds = ViewboxFloatingBar.TransformToAncestor(this).TransformBounds(
|
||||
new Rect(0, 0, ViewboxFloatingBar.ActualWidth, ViewboxFloatingBar.ActualHeight));
|
||||
|
||||
// 如果触摸发生在浮动栏区域,不阻止事件传播,让浮动栏按钮能够接收触摸事件
|
||||
if (floatingBarBounds.Contains(touchPoint.Position))
|
||||
{
|
||||
// 不设置 ViewboxFloatingBar.IsHitTestVisible = false,让浮动栏按钮能够接收触摸事件
|
||||
return;
|
||||
}
|
||||
|
||||
if (inkCanvas.EditingMode == InkCanvasEditingMode.EraseByPoint
|
||||
|| inkCanvas.EditingMode == InkCanvasEditingMode.EraseByStroke
|
||||
|| inkCanvas.EditingMode == InkCanvasEditingMode.Select) return;
|
||||
@@ -139,6 +151,18 @@ namespace Ink_Canvas
|
||||
|
||||
private void MainWindow_StylusDown(object sender, StylusDownEventArgs e)
|
||||
{
|
||||
// 检查手写笔点击是否发生在浮动栏区域,如果是则允许事件传播到浮动栏按钮
|
||||
var stylusPoint = e.GetPosition(this);
|
||||
var floatingBarBounds = ViewboxFloatingBar.TransformToAncestor(this).TransformBounds(
|
||||
new Rect(0, 0, ViewboxFloatingBar.ActualWidth, ViewboxFloatingBar.ActualHeight));
|
||||
|
||||
// 如果手写笔点击发生在浮动栏区域,不阻止事件传播,让浮动栏按钮能够接收手写笔事件
|
||||
if (floatingBarBounds.Contains(stylusPoint))
|
||||
{
|
||||
// 不设置 ViewboxFloatingBar.IsHitTestVisible = false,让浮动栏按钮能够接收手写笔事件
|
||||
return;
|
||||
}
|
||||
|
||||
LogHelper.WriteLogToFile($"MainWindow_StylusDown 被调用,笔尾状态: {e.StylusDevice.Inverted}, 当前 drawingShapeMode: {drawingShapeMode}, 当前 EditingMode: {inkCanvas.EditingMode}", LogHelper.LogType.Info);
|
||||
|
||||
// 新增:根据是否为笔尾自动切换橡皮擦/画笔模式
|
||||
@@ -323,6 +347,18 @@ namespace Ink_Canvas
|
||||
|
||||
private void Main_Grid_TouchDown(object sender, TouchEventArgs e)
|
||||
{
|
||||
// 检查触摸是否发生在浮动栏区域,如果是则允许事件传播到浮动栏按钮
|
||||
var touchPoint = e.GetTouchPoint(this);
|
||||
var floatingBarBounds = ViewboxFloatingBar.TransformToAncestor(this).TransformBounds(
|
||||
new Rect(0, 0, ViewboxFloatingBar.ActualWidth, ViewboxFloatingBar.ActualHeight));
|
||||
|
||||
// 如果触摸发生在浮动栏区域,不阻止事件传播,让浮动栏按钮能够接收触摸事件
|
||||
if (floatingBarBounds.Contains(touchPoint.Position))
|
||||
{
|
||||
// 不设置 ViewboxFloatingBar.IsHitTestVisible = false,让浮动栏按钮能够接收触摸事件
|
||||
return;
|
||||
}
|
||||
|
||||
SetCursorBasedOnEditingMode(inkCanvas);
|
||||
inkCanvas.CaptureTouch(e.TouchDevice);
|
||||
|
||||
@@ -365,11 +401,24 @@ namespace Ink_Canvas
|
||||
private bool palmEraserWasEnabledBeforeMultiTouch;
|
||||
private bool palmEraserTouchDownHandled = false; // 新增:标记手掌擦触摸按下是否已处理
|
||||
private DateTime palmEraserActivationTime; // 新增:记录手掌擦激活时间
|
||||
private const int PALM_ERASER_TIMEOUT_MS = 5000; // 新增:手掌擦超时时间(5秒)
|
||||
private const int PALM_ERASER_TIMEOUT_MS = 3000; // 修改:减少手掌擦超时时间(3秒)
|
||||
private System.Windows.Threading.DispatcherTimer palmEraserRecoveryTimer; // 新增:手掌擦恢复定时器
|
||||
private HashSet<int> palmEraserTouchIds = new HashSet<int>(); // 新增:记录参与手掌擦的触摸点ID
|
||||
|
||||
private void inkCanvas_PreviewTouchDown(object sender, TouchEventArgs e)
|
||||
{
|
||||
// 检查触摸是否发生在浮动栏区域,如果是则允许事件传播到浮动栏按钮
|
||||
var touchPoint = e.GetTouchPoint(this);
|
||||
var floatingBarBounds = ViewboxFloatingBar.TransformToAncestor(this).TransformBounds(
|
||||
new Rect(0, 0, ViewboxFloatingBar.ActualWidth, ViewboxFloatingBar.ActualHeight));
|
||||
|
||||
// 如果触摸发生在浮动栏区域,不阻止事件传播,让浮动栏按钮能够接收触摸事件
|
||||
if (floatingBarBounds.Contains(touchPoint.Position))
|
||||
{
|
||||
// 不设置 ViewboxFloatingBar.IsHitTestVisible = false,让浮动栏按钮能够接收触摸事件
|
||||
return;
|
||||
}
|
||||
|
||||
// 橡皮状态下不做任何切换,直接return,保证橡皮可持续
|
||||
if (inkCanvas.EditingMode == InkCanvasEditingMode.EraseByPoint
|
||||
|| inkCanvas.EditingMode == InkCanvasEditingMode.EraseByStroke)
|
||||
@@ -390,21 +439,21 @@ namespace Ink_Canvas
|
||||
// 修复:几何绘制模式下,只记录几何绘制的起点,不记录触摸轨迹
|
||||
if (dec.Count == 0)
|
||||
{
|
||||
var touchPoint = e.GetTouchPoint(inkCanvas);
|
||||
var inkTouchPoint = e.GetTouchPoint(inkCanvas);
|
||||
// 对于双曲线绘制,第一笔时记录起点,第二笔时不更新起点
|
||||
if (drawingShapeMode == 24 || drawingShapeMode == 25)
|
||||
{
|
||||
// 双曲线绘制:第一笔记录起点,第二笔保持第一笔的起点
|
||||
if (drawMultiStepShapeCurrentStep == 0)
|
||||
{
|
||||
iniP = touchPoint.Position;
|
||||
iniP = inkTouchPoint.Position;
|
||||
}
|
||||
// 第二笔时不更新iniP,保持第一笔的起点
|
||||
}
|
||||
else
|
||||
{
|
||||
// 其他图形正常记录起点
|
||||
iniP = touchPoint.Position;
|
||||
iniP = inkTouchPoint.Position;
|
||||
}
|
||||
lastTouchDownStrokeCollection = inkCanvas.Strokes.Clone();
|
||||
}
|
||||
@@ -419,16 +468,57 @@ namespace Ink_Canvas
|
||||
BlackboardUIGridForInkReplay.IsHitTestVisible = false;
|
||||
dec.Add(e.TouchDevice.Id);
|
||||
|
||||
// Palm Eraser 逻辑 - 修复:只在触摸按下时处理一次,避免重复触发
|
||||
// Palm Eraser 逻辑 - 优化:改进手掌判定条件,提高精度
|
||||
if (Settings.Canvas.EnablePalmEraser && dec.Count >= 2 && !isPalmEraserActive && !palmEraserTouchDownHandled)
|
||||
{
|
||||
var bounds = e.GetTouchPoint(inkCanvas).Bounds;
|
||||
double palmThreshold = 40; // 触摸面积阈值,可根据实际调整
|
||||
if (bounds.Width >= palmThreshold || bounds.Height >= palmThreshold)
|
||||
|
||||
// 根据敏感度设置调整判定参数
|
||||
double palmThreshold;
|
||||
double aspectRatioThreshold;
|
||||
int minTouchPoints;
|
||||
|
||||
switch (Settings.Canvas.PalmEraserSensitivity)
|
||||
{
|
||||
case 0: // 低敏感度 - 更严格的判定
|
||||
palmThreshold = 80;
|
||||
aspectRatioThreshold = 0.4;
|
||||
minTouchPoints = 4;
|
||||
break;
|
||||
case 1: // 中敏感度 - 平衡的判定
|
||||
palmThreshold = 60;
|
||||
aspectRatioThreshold = 0.3;
|
||||
minTouchPoints = 3;
|
||||
break;
|
||||
case 2: // 高敏感度 - 较宽松的判定
|
||||
default:
|
||||
palmThreshold = 50;
|
||||
aspectRatioThreshold = 0.25;
|
||||
minTouchPoints = 2;
|
||||
break;
|
||||
}
|
||||
|
||||
// 计算宽高比
|
||||
double aspectRatio = Math.Min(bounds.Width, bounds.Height) / Math.Max(bounds.Width, bounds.Height);
|
||||
|
||||
// 更严格的手掌判定条件
|
||||
bool isLargeTouch = bounds.Width >= palmThreshold && bounds.Height >= palmThreshold;
|
||||
bool isPalmLikeShape = aspectRatio >= aspectRatioThreshold;
|
||||
bool hasMultipleTouchPoints = dec.Count >= minTouchPoints;
|
||||
|
||||
if (isLargeTouch && isPalmLikeShape && hasMultipleTouchPoints)
|
||||
{
|
||||
// 记录当前编辑模式和高光状态
|
||||
palmEraserLastEditingMode = inkCanvas.EditingMode;
|
||||
palmEraserLastIsHighlighter = drawingAttributes.IsHighlighter;
|
||||
|
||||
// 记录参与手掌擦的触摸点ID
|
||||
palmEraserTouchIds.Clear();
|
||||
foreach (int touchId in dec)
|
||||
{
|
||||
palmEraserTouchIds.Add(touchId);
|
||||
}
|
||||
|
||||
// 切换为橡皮擦
|
||||
EraserIcon_Click(null, null);
|
||||
isPalmEraserActive = true;
|
||||
@@ -437,13 +527,16 @@ namespace Ink_Canvas
|
||||
|
||||
// 启动恢复定时器,防止卡死
|
||||
StartPalmEraserRecoveryTimer();
|
||||
|
||||
// 记录日志
|
||||
LogHelper.WriteLogToFile($"Palm eraser activated - Sensitivity: {Settings.Canvas.PalmEraserSensitivity}, Touch bounds: {bounds.Width}x{bounds.Height}, Aspect ratio: {aspectRatio:F2}, Touch points: {dec.Count}", LogHelper.LogType.Info);
|
||||
}
|
||||
}
|
||||
|
||||
// 设备1个的时候,记录中心点
|
||||
if (dec.Count == 1)
|
||||
{
|
||||
var touchPoint = e.GetTouchPoint(inkCanvas);
|
||||
touchPoint = e.GetTouchPoint(inkCanvas);
|
||||
centerPoint = touchPoint.Position;
|
||||
|
||||
// 修复:只允许在此处赋值iniP,防止TouchMove等其他地方覆盖,保证几何绘制起点一致
|
||||
@@ -497,41 +590,54 @@ namespace Ink_Canvas
|
||||
ViewboxFloatingBar.IsHitTestVisible = true;
|
||||
BlackboardUIGridForInkReplay.IsHitTestVisible = true;
|
||||
|
||||
// Palm Eraser 逻辑:所有点抬起后恢复原编辑模式
|
||||
// Palm Eraser 逻辑:优化状态恢复机制
|
||||
dec.Remove(e.TouchDevice.Id);
|
||||
if (isPalmEraserActive && dec.Count == 0)
|
||||
|
||||
// 如果是手掌擦的触摸点,从记录中移除
|
||||
if (palmEraserTouchIds.Contains(e.TouchDevice.Id))
|
||||
{
|
||||
palmEraserTouchIds.Remove(e.TouchDevice.Id);
|
||||
}
|
||||
|
||||
// 当所有手掌擦触摸点都抬起时,恢复原编辑模式
|
||||
if (isPalmEraserActive && palmEraserTouchIds.Count == 0)
|
||||
{
|
||||
// 恢复高光状态
|
||||
drawingAttributes.IsHighlighter = palmEraserLastIsHighlighter;
|
||||
// 恢复编辑模式 - 修复:确保正确恢复状态
|
||||
|
||||
// 恢复编辑模式 - 优化:改进状态恢复逻辑
|
||||
try
|
||||
{
|
||||
if (inkCanvas.EditingMode == InkCanvasEditingMode.EraseByPoint)
|
||||
{
|
||||
if (palmEraserLastEditingMode == InkCanvasEditingMode.Ink)
|
||||
// 根据之前的状态恢复
|
||||
switch (palmEraserLastEditingMode)
|
||||
{
|
||||
PenIcon_Click(null, null);
|
||||
}
|
||||
else if (palmEraserLastEditingMode == InkCanvasEditingMode.Select)
|
||||
{
|
||||
SymbolIconSelect_MouseUp(null, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
inkCanvas.EditingMode = palmEraserLastEditingMode;
|
||||
case InkCanvasEditingMode.Ink:
|
||||
PenIcon_Click(null, null);
|
||||
break;
|
||||
case InkCanvasEditingMode.Select:
|
||||
SymbolIconSelect_MouseUp(null, null);
|
||||
break;
|
||||
default:
|
||||
inkCanvas.EditingMode = palmEraserLastEditingMode;
|
||||
break;
|
||||
}
|
||||
|
||||
LogHelper.WriteLogToFile($"Palm eraser recovered to mode: {palmEraserLastEditingMode}", LogHelper.LogType.Info);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// 如果恢复失败,强制切换到批注模式
|
||||
Trace.WriteLine($"Palm eraser recovery failed: {ex.Message}, forcing to Ink mode");
|
||||
LogHelper.WriteLogToFile($"Palm eraser recovery failed: {ex.Message}, forcing to Ink mode", LogHelper.LogType.Error);
|
||||
inkCanvas.EditingMode = InkCanvasEditingMode.Ink;
|
||||
}
|
||||
|
||||
// 重置手掌擦状态
|
||||
isPalmEraserActive = false;
|
||||
palmEraserTouchDownHandled = false;
|
||||
palmEraserTouchIds.Clear();
|
||||
|
||||
// 停止恢复定时器
|
||||
StopPalmEraserRecoveryTimer();
|
||||
@@ -542,44 +648,47 @@ namespace Ink_Canvas
|
||||
|
||||
ViewboxFloatingBar.IsHitTestVisible = true;
|
||||
BlackboardUIGridForInkReplay.IsHitTestVisible = true;
|
||||
|
||||
LogHelper.WriteLogToFile("Palm eraser state reset completed", LogHelper.LogType.Info);
|
||||
}
|
||||
|
||||
// 新增:超时检测 - 如果手掌擦激活时间过长,强制重置状态
|
||||
if (isPalmEraserActive && dec.Count == 0)
|
||||
if (isPalmEraserActive)
|
||||
{
|
||||
var timeSinceActivation = DateTime.Now - palmEraserActivationTime;
|
||||
if (timeSinceActivation.TotalMilliseconds > PALM_ERASER_TIMEOUT_MS)
|
||||
{
|
||||
Trace.WriteLine($"Palm eraser timeout detected ({timeSinceActivation.TotalMilliseconds}ms), forcing recovery");
|
||||
LogHelper.WriteLogToFile($"Palm eraser timeout detected ({timeSinceActivation.TotalMilliseconds}ms), forcing recovery", LogHelper.LogType.Warning);
|
||||
|
||||
// 强制恢复状态
|
||||
try
|
||||
{
|
||||
if (inkCanvas.EditingMode == InkCanvasEditingMode.EraseByPoint)
|
||||
{
|
||||
if (palmEraserLastEditingMode == InkCanvasEditingMode.Ink)
|
||||
switch (palmEraserLastEditingMode)
|
||||
{
|
||||
PenIcon_Click(null, null);
|
||||
}
|
||||
else if (palmEraserLastEditingMode == InkCanvasEditingMode.Select)
|
||||
{
|
||||
SymbolIconSelect_MouseUp(null, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
inkCanvas.EditingMode = palmEraserLastEditingMode;
|
||||
case InkCanvasEditingMode.Ink:
|
||||
PenIcon_Click(null, null);
|
||||
break;
|
||||
case InkCanvasEditingMode.Select:
|
||||
SymbolIconSelect_MouseUp(null, null);
|
||||
break;
|
||||
default:
|
||||
inkCanvas.EditingMode = palmEraserLastEditingMode;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Trace.WriteLine($"Palm eraser timeout recovery failed: {ex.Message}, forcing to Ink mode");
|
||||
LogHelper.WriteLogToFile($"Palm eraser timeout recovery failed: {ex.Message}, forcing to Ink mode", LogHelper.LogType.Error);
|
||||
inkCanvas.EditingMode = InkCanvasEditingMode.Ink;
|
||||
}
|
||||
|
||||
// 重置所有手掌擦状态
|
||||
isPalmEraserActive = false;
|
||||
palmEraserTouchDownHandled = false;
|
||||
palmEraserTouchIds.Clear();
|
||||
inkCanvas.IsHitTestVisible = true;
|
||||
inkCanvas.IsManipulationEnabled = true;
|
||||
|
||||
@@ -588,6 +697,8 @@ namespace Ink_Canvas
|
||||
|
||||
// 停止恢复定时器
|
||||
StopPalmEraserRecoveryTimer();
|
||||
|
||||
LogHelper.WriteLogToFile("Palm eraser timeout recovery completed", LogHelper.LogType.Info);
|
||||
}
|
||||
}
|
||||
// 修复:几何绘制模式下,触摸抬手时应该正确处理,而不是简单模拟鼠标事件
|
||||
@@ -656,6 +767,7 @@ namespace Ink_Canvas
|
||||
// 如果手掌擦还在激活状态但触摸点已清空,强制重置状态
|
||||
isPalmEraserActive = false;
|
||||
palmEraserTouchDownHandled = false;
|
||||
palmEraserTouchIds.Clear(); // 确保清空触摸点ID
|
||||
inkCanvas.IsHitTestVisible = true;
|
||||
inkCanvas.IsManipulationEnabled = true;
|
||||
|
||||
@@ -902,36 +1014,39 @@ namespace Ink_Canvas
|
||||
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");
|
||||
LogHelper.WriteLogToFile($"Palm eraser recovery timer triggered, forcing recovery after {timeSinceActivation.TotalMilliseconds}ms", LogHelper.LogType.Warning);
|
||||
|
||||
// 强制恢复状态
|
||||
try
|
||||
{
|
||||
if (inkCanvas.EditingMode == InkCanvasEditingMode.EraseByPoint)
|
||||
{
|
||||
if (palmEraserLastEditingMode == InkCanvasEditingMode.Ink)
|
||||
switch (palmEraserLastEditingMode)
|
||||
{
|
||||
PenIcon_Click(null, null);
|
||||
}
|
||||
else if (palmEraserLastEditingMode == InkCanvasEditingMode.Select)
|
||||
{
|
||||
SymbolIconSelect_MouseUp(null, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
inkCanvas.EditingMode = palmEraserLastEditingMode;
|
||||
case InkCanvasEditingMode.Ink:
|
||||
PenIcon_Click(null, null);
|
||||
break;
|
||||
case InkCanvasEditingMode.Select:
|
||||
SymbolIconSelect_MouseUp(null, null);
|
||||
break;
|
||||
default:
|
||||
inkCanvas.EditingMode = palmEraserLastEditingMode;
|
||||
break;
|
||||
}
|
||||
|
||||
LogHelper.WriteLogToFile($"Palm eraser timer recovery to mode: {palmEraserLastEditingMode}", LogHelper.LogType.Info);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Trace.WriteLine($"Palm eraser recovery timer failed: {ex.Message}, forcing to Ink mode");
|
||||
LogHelper.WriteLogToFile($"Palm eraser recovery timer failed: {ex.Message}, forcing to Ink mode", LogHelper.LogType.Error);
|
||||
inkCanvas.EditingMode = InkCanvasEditingMode.Ink;
|
||||
}
|
||||
|
||||
// 重置所有手掌擦状态
|
||||
isPalmEraserActive = false;
|
||||
palmEraserTouchDownHandled = false;
|
||||
palmEraserTouchIds.Clear();
|
||||
inkCanvas.IsHitTestVisible = true;
|
||||
inkCanvas.IsManipulationEnabled = true;
|
||||
|
||||
@@ -940,6 +1055,8 @@ namespace Ink_Canvas
|
||||
|
||||
// 停止定时器
|
||||
StopPalmEraserRecoveryTimer();
|
||||
|
||||
LogHelper.WriteLogToFile("Palm eraser timer recovery completed", LogHelper.LogType.Info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System.Reflection;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows;
|
||||
|
||||
@@ -10,7 +10,7 @@ using System.Windows;
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("CJK_mkp")]
|
||||
[assembly: AssemblyProduct("InkCanvasForClass")]
|
||||
[assembly: AssemblyCopyright("© Copyright HARKOTEK Studio 2024-now")]
|
||||
[assembly: AssemblyCopyright("Copyright © HARKOTEK Studio 2024")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
@@ -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.8.0")]
|
||||
[assembly: AssemblyFileVersion("1.7.8.0")]
|
||||
[assembly: AssemblyVersion("1.7.8.3")]
|
||||
[assembly: AssemblyFileVersion("1.7.8.3")]
|
||||
|
||||
@@ -88,6 +88,8 @@ namespace Ink_Canvas
|
||||
public bool IsCompressPicturesUploaded { get; set; }
|
||||
[JsonProperty("enablePalmEraser")]
|
||||
public bool EnablePalmEraser { get; set; } = true;
|
||||
[JsonProperty("palmEraserSensitivity")]
|
||||
public int PalmEraserSensitivity { get; set; } = 2; // 0-低敏感度, 1-中敏感度, 2-高敏感度
|
||||
[JsonProperty("clearCanvasAlsoClearImages")]
|
||||
public bool ClearCanvasAlsoClearImages { get; set; } = true;
|
||||
[JsonProperty("showCircleCenter")]
|
||||
|
||||
@@ -340,7 +340,7 @@ namespace Ink_Canvas
|
||||
downloadUrl = Path.Combine(updatesFolderPath, $"InkCanvasForClass.CE.{version}.zip");
|
||||
}
|
||||
LogHelper.WriteLogToFile($"AutoUpdate | 开始安装版本: {version}");
|
||||
AutoUpdateHelper.InstallNewVersionApp(version, false);
|
||||
AutoUpdateHelper.InstallNewVersionApp(version, true);
|
||||
App.IsAppExitByUser = true;
|
||||
Application.Current.Dispatcher.Invoke(() =>
|
||||
{
|
||||
|
||||
@@ -94,6 +94,7 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" valign="top" width="14.28%"><a href="https://github.com/PrefacedCorg"><img src="https://avatars.githubusercontent.com/u/129855423?v=4?s=100" width="100px;" alt="PrefacedCorg"/><br /><sub><b>PrefacedCorg</b></sub></a><br /><a href="#code-PrefacedCorg" title="Code">💻</a> <a href="#design-PrefacedCorg" title="Design">🎨</a></td>
|
||||
<td align="center" valign="top" width="14.28%"><a href="http://blog.jursin.top"><img src="https://avatars.githubusercontent.com/u/127487914?v=4?s=100" width="100px;" alt="Jursin"/><br /><sub><b>Jursin</b></sub></a><br /><a href="#design-Jursin" title="Design">🎨</a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
ICC CE 1.7.X.X更新日志
|
||||
1. 改进端点吸附
|
||||
2. 新增自定义浮动栏图标
|
||||
3. 新增自定义点名背景
|
||||
@@ -51,3 +52,6 @@
|
||||
51. 优化调色板
|
||||
52. 修复浮动栏动画异常
|
||||
53. 修复开关状态异常
|
||||
54. 优化浮动栏触摸点击
|
||||
55. 优化快捷键
|
||||
|
||||
|
||||
Reference in New Issue
Block a user