Merge pull request #147 from InkCanvasForClass/beta

ICC CE 1.7.9.1
This commit is contained in:
CJK_mkp
2025-08-31 12:39:00 +08:00
committed by GitHub
69 changed files with 1509 additions and 810 deletions
+50 -6
View File
@@ -1,3 +1,8 @@
using Hardcodet.Wpf.TaskbarNotification;
using Ink_Canvas.Helpers;
using iNKORE.UI.WPF.Modern.Controls;
using Microsoft.Win32;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Diagnostics;
@@ -13,11 +18,6 @@ using System.Windows;
using System.Windows.Forms;
using System.Windows.Input;
using System.Windows.Threading;
using Hardcodet.Wpf.TaskbarNotification;
using Ink_Canvas.Helpers;
using iNKORE.UI.WPF.Modern.Controls;
using Microsoft.Win32;
using Newtonsoft.Json;
using Application = System.Windows.Application;
using MessageBox = System.Windows.MessageBox;
using Timer = System.Threading.Timer;
@@ -633,7 +633,28 @@ namespace Ink_Canvas
if (!ret && !e.Args.Contains("-m")) //-m multiple
{
LogHelper.NewLog("Detected existing instance");
MessageBox.Show("已有一个程序实例正在运行");
// 检查是否有.icstk文件参数
string icstkFile = FileAssociationManager.GetIcstkFileFromArgs(e.Args);
if (!string.IsNullOrEmpty(icstkFile))
{
LogHelper.WriteLogToFile($"检测到已运行实例,尝试通过IPC发送文件: {icstkFile}", LogHelper.LogType.Event);
// 尝试通过IPC发送文件路径给已运行实例
if (FileAssociationManager.TrySendFileToExistingInstance(icstkFile))
{
LogHelper.WriteLogToFile("文件路径已通过IPC发送给已运行实例", LogHelper.LogType.Event);
}
else
{
LogHelper.WriteLogToFile("通过IPC发送文件路径失败", LogHelper.LogType.Warning);
}
}
else
{
LogHelper.WriteLogToFile("检测到已运行实例,但无文件参数", LogHelper.LogType.Event);
}
LogHelper.NewLog("Ink Canvas automatically closed");
IsAppExitByUser = true; // 多开时标记为用户主动退出
// 写入退出信号,确保看门狗不会重启
@@ -687,6 +708,29 @@ namespace Ink_Canvas
MainWindow = mainWindow;
mainWindow.Show();
// 新增:注册.icstk文件关联
try
{
LogHelper.WriteLogToFile("开始注册.icstk文件关联");
FileAssociationManager.RegisterFileAssociation();
FileAssociationManager.ShowFileAssociationStatus();
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"注册文件关联时出错: {ex.Message}", LogHelper.LogType.Error);
}
// 新增:启动IPC监听器
try
{
LogHelper.WriteLogToFile("启动IPC监听器");
FileAssociationManager.StartIpcListener();
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"启动IPC监听器时出错: {ex.Message}", LogHelper.LogType.Error);
}
// 新增:Office注册表检测
try
{
+2 -2
View File
@@ -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.9.0")]
[assembly: AssemblyFileVersion("1.7.9.0")]
[assembly: AssemblyVersion("1.7.9.1")]
[assembly: AssemblyFileVersion("1.7.9.1")]
+7 -7
View File
@@ -1,3 +1,5 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
@@ -15,8 +17,6 @@ using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace Ink_Canvas.Helpers
{
@@ -1365,7 +1365,7 @@ namespace Ink_Canvas.Helpers
// 启动更新任务
Task.Run(async () => await PerformUpdate(oldProcessId, extractPath, targetPath, isSilence));
return true; // 返回true表示是更新模式
}
}
LogHelper.WriteLogToFile($"AutoUpdate | 参数验证失败 - 老进程ID: {oldProcessId}, 解压路径: {extractPath}, 目标路径: {targetPath}", LogHelper.LogType.Error);
return false;
@@ -1445,9 +1445,9 @@ namespace Ink_Canvas.Helpers
if (copySuccess)
{
LogHelper.WriteLogToFile("AutoUpdate | 文件复制完成");
}
else
{
}
else
{
LogHelper.WriteLogToFile("AutoUpdate | 文件复制失败,部分文件可能无法覆盖", LogHelper.LogType.Error);
if (!isSilence)
@@ -1503,7 +1503,7 @@ namespace Ink_Canvas.Helpers
LogHelper.WriteLogToFile("AutoUpdate | 更新操作完成");
// 启动更新后的应用程序
// 启动更新后的应用程序
string newAppPath = Path.Combine(targetPath, "InkCanvasForClass.exe");
if (File.Exists(newAppPath))
{
+13 -13
View File
@@ -1,3 +1,4 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
@@ -5,7 +6,6 @@ using System.Linq;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;
using Newtonsoft.Json;
namespace Ink_Canvas.Helpers
{
@@ -758,21 +758,21 @@ namespace Ink_Canvas.Helpers
// 如果所有文件都不存在或损坏,返回新的统计对象
var newStats = new UsageStats
{
DeviceId = DeviceId,
LastLaunchTime = DateTime.Now,
LaunchCount = 0,
TotalUsageSeconds = 0,
AverageSessionSeconds = 0,
LastUpdateCheck = DateTime.MinValue,
UpdatePriority = UpdatePriority.Medium,
UsageFrequency = UsageFrequency.Medium
};
var newStats = new UsageStats
{
DeviceId = DeviceId,
LastLaunchTime = DateTime.Now,
LaunchCount = 0,
TotalUsageSeconds = 0,
AverageSessionSeconds = 0,
LastUpdateCheck = DateTime.MinValue,
UpdatePriority = UpdatePriority.Medium,
UsageFrequency = UsageFrequency.Medium
};
// 保存新统计到文件
SaveUsageStatsToFile(UsageStatsFilePath, newStats);
return newStats;
return newStats;
}
catch (Exception ex)
{
@@ -0,0 +1,380 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Security;
using System.Windows;
using Microsoft.Win32;
using System.Threading;
using System.Text;
namespace Ink_Canvas.Helpers
{
/// <summary>
/// 文件关联管理器,用于注册和处理.icstk文件的关联
/// </summary>
public static class FileAssociationManager
{
private const string FileExtension = ".icstk";
private const string FileTypeName = "InkCanvasStrokesFile";
private const string AppName = "Ink Canvas";
private const string AppDescription = "Ink Canvas Strokes File";
// IPC相关常量
private const string IpcMutexName = "InkCanvasFileAssociationIpc";
private const string IpcEventName = "InkCanvasFileAssociationEvent";
private const string IpcFilePrefix = "InkCanvasFileAssociation_";
private const int IpcTimeout = 5000; // 5秒超时
/// <summary>
/// 注册.icstk文件关联
/// </summary>
public static bool RegisterFileAssociation()
{
try
{
string exePath = Process.GetCurrentProcess().MainModule.FileName;
// 注册文件类型
using (RegistryKey fileTypeKey = Registry.ClassesRoot.CreateSubKey(FileTypeName))
{
fileTypeKey.SetValue("", AppDescription);
fileTypeKey.SetValue("FriendlyTypeName", AppDescription);
// 设置默认图标
using (RegistryKey defaultIconKey = fileTypeKey.CreateSubKey("DefaultIcon"))
{
defaultIconKey.SetValue("", $"\"{exePath}\",0");
}
// 设置打开命令
using (RegistryKey shellKey = fileTypeKey.CreateSubKey("shell"))
using (RegistryKey openKey = shellKey.CreateSubKey("open"))
using (RegistryKey commandKey = openKey.CreateSubKey("command"))
{
commandKey.SetValue("", $"\"{exePath}\" \"%1\"");
}
}
// 注册文件扩展名
using (RegistryKey extensionKey = Registry.ClassesRoot.CreateSubKey(FileExtension))
{
extensionKey.SetValue("", FileTypeName);
}
// 刷新系统文件关联缓存
RefreshSystemFileAssociations();
LogHelper.WriteLogToFile($"成功注册{FileExtension}文件关联", LogHelper.LogType.Event);
return true;
}
catch (SecurityException ex)
{
LogHelper.WriteLogToFile($"注册文件关联时权限不足: {ex.Message}", LogHelper.LogType.Error);
return false;
}
catch (UnauthorizedAccessException ex)
{
LogHelper.WriteLogToFile($"注册文件关联时访问被拒绝: {ex.Message}", LogHelper.LogType.Error);
return false;
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"注册文件关联时出错: {ex.Message}", LogHelper.LogType.Error);
return false;
}
}
/// <summary>
/// 注销.icstk文件关联
/// </summary>
public static bool UnregisterFileAssociation()
{
try
{
// 删除文件扩展名关联
Registry.ClassesRoot.DeleteSubKeyTree(FileExtension, false);
// 删除文件类型定义
Registry.ClassesRoot.DeleteSubKeyTree(FileTypeName, false);
// 刷新系统文件关联缓存
RefreshSystemFileAssociations();
LogHelper.WriteLogToFile($"成功注销{FileExtension}文件关联", LogHelper.LogType.Event);
return true;
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"注销文件关联时出错: {ex.Message}", LogHelper.LogType.Error);
return false;
}
}
/// <summary>
/// 检查文件关联是否已注册
/// </summary>
public static bool IsFileAssociationRegistered()
{
try
{
using (RegistryKey extensionKey = Registry.ClassesRoot.OpenSubKey(FileExtension))
{
if (extensionKey == null) return false;
string fileType = extensionKey.GetValue("") as string;
if (string.IsNullOrEmpty(fileType)) return false;
using (RegistryKey fileTypeKey = Registry.ClassesRoot.OpenSubKey(fileType))
{
if (fileTypeKey == null) return false;
using (RegistryKey shellKey = fileTypeKey.OpenSubKey("shell\\open\\command"))
{
if (shellKey == null) return false;
string command = shellKey.GetValue("") as string;
if (string.IsNullOrEmpty(command)) return false;
// 检查命令是否指向当前应用程序
string currentExePath = Process.GetCurrentProcess().MainModule.FileName;
return command.Contains(currentExePath);
}
}
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"检查文件关联状态时出错: {ex.Message}", LogHelper.LogType.Error);
}
return false;
}
/// <summary>
/// 显示文件关联状态
/// </summary>
public static void ShowFileAssociationStatus()
{
bool isRegistered = IsFileAssociationRegistered();
LogHelper.WriteLogToFile($"{FileExtension}文件关联状态: {(isRegistered ? "" : "")}", LogHelper.LogType.Event);
}
/// <summary>
/// 刷新系统文件关联缓存
/// </summary>
private static void RefreshSystemFileAssociations()
{
try
{
// 通知系统文件关联已更改
SHChangeNotify(0x08000000, 0, IntPtr.Zero, IntPtr.Zero);
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"刷新文件关联缓存时出错: {ex.Message}", LogHelper.LogType.Warning);
}
}
/// <summary>
/// 处理命令行参数中的文件路径
/// </summary>
/// <param name="args">命令行参数</param>
/// <returns>找到的.icstk文件路径,如果没有找到则返回null</returns>
public static string GetIcstkFileFromArgs(string[] args)
{
if (args == null || args.Length == 0) return null;
foreach (string arg in args)
{
if (string.IsNullOrEmpty(arg)) continue;
// 检查是否为.icstk文件
if (Path.GetExtension(arg).Equals(FileExtension, StringComparison.OrdinalIgnoreCase))
{
// 检查文件是否存在
if (File.Exists(arg))
{
LogHelper.WriteLogToFile($"从命令行参数中找到.icstk文件: {arg}", LogHelper.LogType.Event);
return arg;
}
else
{
LogHelper.WriteLogToFile($"命令行参数中的.icstk文件不存在: {arg}", LogHelper.LogType.Warning);
}
}
}
return null;
}
/// <summary>
/// 尝试通过IPC将文件路径发送给已运行的实例
/// </summary>
/// <param name="filePath">要打开的文件路径</param>
/// <returns>是否成功发送</returns>
public static bool TrySendFileToExistingInstance(string filePath)
{
try
{
LogHelper.WriteLogToFile($"尝试通过IPC发送文件路径给已运行实例: {filePath}", LogHelper.LogType.Event);
// 创建IPC文件
string tempDir = Path.GetTempPath();
string ipcFileName = IpcFilePrefix + Guid.NewGuid().ToString("N") + ".tmp";
string ipcFilePath = Path.Combine(tempDir, ipcFileName);
// 写入文件路径到IPC文件
File.WriteAllText(ipcFilePath, filePath, Encoding.UTF8);
// 创建事件通知已运行实例
using (EventWaitHandle ipcEvent = new EventWaitHandle(false, EventResetMode.ManualReset, IpcEventName))
{
ipcEvent.Set();
}
// 等待一段时间让已运行实例处理文件
Thread.Sleep(1000);
// 清理IPC文件
try
{
if (File.Exists(ipcFilePath))
{
File.Delete(ipcFilePath);
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"清理IPC文件失败: {ex.Message}", LogHelper.LogType.Warning);
}
LogHelper.WriteLogToFile("IPC文件路径发送完成", LogHelper.LogType.Event);
return true;
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"通过IPC发送文件路径失败: {ex.Message}", LogHelper.LogType.Error);
return false;
}
}
/// <summary>
/// 启动IPC监听器,等待其他实例发送文件路径
/// </summary>
public static void StartIpcListener()
{
try
{
Thread ipcThread = new Thread(() =>
{
try
{
LogHelper.WriteLogToFile("启动IPC监听器", LogHelper.LogType.Event);
using (EventWaitHandle ipcEvent = new EventWaitHandle(false, EventResetMode.ManualReset, IpcEventName))
{
while (true)
{
// 等待IPC事件
if (ipcEvent.WaitOne(IpcTimeout))
{
// 处理IPC文件
ProcessIpcFiles();
// 重置事件
ipcEvent.Reset();
}
// 检查应用是否还在运行
if (Application.Current == null || Application.Current.Dispatcher == null)
{
break;
}
}
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"IPC监听器出错: {ex.Message}", LogHelper.LogType.Error);
}
});
ipcThread.IsBackground = true;
ipcThread.Start();
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"启动IPC监听器失败: {ex.Message}", LogHelper.LogType.Error);
}
}
/// <summary>
/// 处理IPC文件
/// </summary>
private static void ProcessIpcFiles()
{
try
{
string tempDir = Path.GetTempPath();
string[] ipcFiles = Directory.GetFiles(tempDir, IpcFilePrefix + "*.tmp");
foreach (string ipcFile in ipcFiles)
{
try
{
// 读取文件路径
string filePath = File.ReadAllText(ipcFile, Encoding.UTF8);
if (!string.IsNullOrEmpty(filePath) && File.Exists(filePath))
{
LogHelper.WriteLogToFile($"IPC接收到文件路径: {filePath}", LogHelper.LogType.Event);
// 在UI线程中处理文件打开
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
try
{
// 获取主窗口并打开文件
if (Application.Current.MainWindow is MainWindow mainWindow)
{
mainWindow.OpenSingleStrokeFile(filePath);
mainWindow.ShowNotification($"已加载墨迹文件: {Path.GetFileName(filePath)}");
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"IPC处理文件打开失败: {ex.Message}", LogHelper.LogType.Error);
}
}));
}
// 删除IPC文件
File.Delete(ipcFile);
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"处理IPC文件失败: {ex.Message}", LogHelper.LogType.Warning);
// 尝试删除损坏的IPC文件
try
{
if (File.Exists(ipcFile))
{
File.Delete(ipcFile);
}
}
catch { }
}
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"处理IPC文件时出错: {ex.Message}", LogHelper.LogType.Error);
}
}
[DllImport("shell32.dll")]
private static extern void SHChangeNotify(uint wEventId, uint uFlags, IntPtr dwItem1, IntPtr dwItem2);
}
}
+2 -2
View File
@@ -1,11 +1,11 @@
using Newtonsoft.Json;
using NHotkey.Wpf;
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Text;
using System.Windows.Input;
using Newtonsoft.Json;
using NHotkey.Wpf;
namespace Ink_Canvas.Helpers
{
+6 -6
View File
@@ -319,12 +319,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);
}
}
// 高亮笔通常需要更宽的笔触来覆盖下面的内容
if (drawingAttribs.Width < 20)
{
path.StrokeThickness = Math.Max(drawingAttribs.Width * 1.5, 20);
}
}
// 不设置任何变换,保持墨迹原有粗细
var bounds = geometry.Bounds;
+2 -2
View File
@@ -1,9 +1,9 @@
using System;
using Microsoft.Office.Interop.PowerPoint;
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using System.Windows.Ink;
using Microsoft.Office.Interop.PowerPoint;
namespace Ink_Canvas.Helpers
{
+2 -2
View File
@@ -1,4 +1,5 @@
using System;
using Microsoft.Office.Interop.PowerPoint;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
@@ -7,7 +8,6 @@ using System.Text;
using System.Threading;
using System.Timers;
using System.Windows.Threading;
using Microsoft.Office.Interop.PowerPoint;
using Application = System.Windows.Application;
using Timer = System.Timers.Timer;
@@ -1,9 +1,9 @@
using iNKORE.UI.WPF.Modern.Controls;
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using iNKORE.UI.WPF.Modern.Controls;
namespace Ink_Canvas.Helpers.Plugins.BuiltIn.SuperLauncher
{
@@ -1,3 +1,5 @@
using Microsoft.Win32;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Diagnostics;
@@ -8,8 +10,6 @@ using System.Windows;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using Microsoft.Win32;
using Newtonsoft.Json;
namespace Ink_Canvas.Helpers.Plugins.BuiltIn.SuperLauncher
{
@@ -1,10 +1,10 @@
using Ink_Canvas.Windows;
using Microsoft.Win32;
using System;
using System.ComponentModel;
using System.IO;
using System.Windows;
using System.Windows.Controls;
using Ink_Canvas.Windows;
using Microsoft.Win32;
namespace Ink_Canvas.Helpers.Plugins.BuiltIn.SuperLauncher
{
@@ -1,3 +1,5 @@
using Ink_Canvas.Helpers.Plugins.BuiltIn.SuperLauncher;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
@@ -5,8 +7,6 @@ using System.IO;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using Ink_Canvas.Helpers.Plugins.BuiltIn.SuperLauncher;
using Newtonsoft.Json;
namespace Ink_Canvas.Helpers.Plugins.BuiltIn
{
@@ -1,8 +1,8 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace Ink_Canvas.Helpers.Plugins
{
+2 -2
View File
@@ -1,3 +1,5 @@
using Ink_Canvas.Windows;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
@@ -8,8 +10,6 @@ using System.Security.Cryptography;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using Ink_Canvas.Windows;
using Newtonsoft.Json;
using Timer = System.Timers.Timer;
namespace Ink_Canvas.Helpers.Plugins
+2 -2
View File
@@ -1,8 +1,8 @@
using System;
using Microsoft.Win32;
using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using Microsoft.Win32;
namespace Ink_Canvas.Helpers
{
+20
View File
@@ -2659,6 +2659,26 @@
</ui:SimpleStackPanel>
<Line HorizontalAlignment="Center" X1="0" Y1="0" X2="400" Y2="0" Stroke="#3f3f46"
StrokeThickness="1" Margin="0,4,0,4" />
<TextBlock Text="文件关联管理" FontWeight="Bold" Foreground="#fafafa"
FontSize="16" Margin="0,8,0,8" />
<TextBlock Text="管理.icstk文件的关联设置,双击.icstk文件可直接在Ink Canvas中打开"
TextWrapping="Wrap" Foreground="#a1a1aa" Margin="0,0,0,8" />
<ui:SimpleStackPanel Orientation="Horizontal" HorizontalAlignment="Left" Margin="0,0,0,8">
<Button Name="BtnUnregisterFileAssociation" Content="取消文件关联"
Padding="12,6" Margin="0,0,8,0" Click="BtnUnregisterFileAssociation_Click"
Background="#FFDC3545" Foreground="White" BorderBrush="#FFBD2130"
FontFamily="Microsoft YaHei UI" FontSize="12" />
<Button Name="BtnCheckFileAssociation" Content="检查关联状态"
Padding="12,6" Margin="0,0,8,0" Click="BtnCheckFileAssociation_Click"
Background="#FF17A2B8" Foreground="White" BorderBrush="#FF138496"
FontFamily="Microsoft YaHei UI" FontSize="12" />
<Button Name="BtnRegisterFileAssociation" Content="重新注册关联"
Padding="12,6" Click="BtnRegisterFileAssociation_Click"
Background="#FF28A745" Foreground="White" BorderBrush="#FF1E7E34"
FontFamily="Microsoft YaHei UI" FontSize="12" />
</ui:SimpleStackPanel>
<TextBlock Name="TextBlockFileAssociationStatus" Text=""
Foreground="#a1a1aa" FontSize="12" Margin="0,4,0,0" />
<ui:SimpleStackPanel Orientation="Horizontal" HorizontalAlignment="Left">
<TextBlock Foreground="#fafafa" Text="清屏时自动截图" VerticalAlignment="Center"
FontSize="14" Margin="0,0,16,0" />
+76 -6
View File
@@ -1,3 +1,9 @@
using Ink_Canvas.Helpers;
using Ink_Canvas.Helpers.Plugins;
using Ink_Canvas.Windows;
using iNKORE.UI.WPF.Modern;
using iNKORE.UI.WPF.Modern.Controls;
using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.ComponentModel;
@@ -16,12 +22,6 @@ using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Threading;
using Ink_Canvas.Helpers;
using Ink_Canvas.Helpers.Plugins;
using Ink_Canvas.Windows;
using iNKORE.UI.WPF.Modern;
using iNKORE.UI.WPF.Modern.Controls;
using Microsoft.Win32;
using Application = System.Windows.Application;
using Brushes = System.Windows.Media.Brushes;
using Button = System.Windows.Controls.Button;
@@ -523,6 +523,12 @@ namespace Ink_Canvas
// 初始化墨迹渐隐管理器
InitializeInkFadeManager();
// 处理命令行参数中的文件路径
HandleCommandLineFileOpen();
// 初始化文件关联状态显示
InitializeFileAssociationStatus();
}
private void SystemEventsOnDisplaySettingsChanged(object sender, EventArgs e)
@@ -2126,6 +2132,70 @@ namespace Ink_Canvas
}
#endregion
/// <summary>
/// 初始化文件关联状态显示
/// </summary>
private void InitializeFileAssociationStatus()
{
try
{
bool isRegistered = FileAssociationManager.IsFileAssociationRegistered();
if (isRegistered)
{
TextBlockFileAssociationStatus.Text = "✓ .icstk文件关联已注册";
TextBlockFileAssociationStatus.Foreground = new SolidColorBrush(Colors.LightGreen);
}
else
{
TextBlockFileAssociationStatus.Text = "✗ .icstk文件关联未注册";
TextBlockFileAssociationStatus.Foreground = new SolidColorBrush(Colors.LightCoral);
}
}
catch (Exception ex)
{
TextBlockFileAssociationStatus.Text = "✗ 检查文件关联状态时出错";
TextBlockFileAssociationStatus.Foreground = new SolidColorBrush(Colors.LightCoral);
LogHelper.WriteLogToFile($"初始化文件关联状态显示时出错: {ex.Message}", LogHelper.LogType.Error);
}
}
/// <summary>
/// 处理命令行参数中的文件路径
/// </summary>
private void HandleCommandLineFileOpen()
{
try
{
// 检查启动参数中是否有.icstk文件
string icstkFile = FileAssociationManager.GetIcstkFileFromArgs(App.StartArgs);
if (!string.IsNullOrEmpty(icstkFile))
{
LogHelper.WriteLogToFile($"检测到命令行参数中的.icstk文件: {icstkFile}", LogHelper.LogType.Event);
// 延迟执行,确保UI已完全加载
Dispatcher.BeginInvoke(new Action(() =>
{
try
{
// 打开文件
OpenSingleStrokeFile(icstkFile);
ShowNotification($"已加载墨迹文件: {Path.GetFileName(icstkFile)}");
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"打开命令行参数中的文件失败: {ex.Message}", LogHelper.LogType.Error);
ShowNotification("打开墨迹文件失败");
}
}), DispatcherPriority.Loaded);
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"处理命令行文件打开时出错: {ex.Message}", LogHelper.LogType.Error);
}
}
/// <summary>
/// 集中管理工具模式切换和快捷键状态更新
/// 避免在每个工具按钮点击时重复刷新快捷键状态
+3 -3
View File
@@ -1,4 +1,6 @@
using System;
using Ink_Canvas.Helpers;
using iNKORE.UI.WPF.Modern;
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
@@ -6,8 +8,6 @@ using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using Ink_Canvas.Helpers;
using iNKORE.UI.WPF.Modern;
namespace Ink_Canvas
{
+2 -2
View File
@@ -1,6 +1,6 @@
using System;
using IWshRuntimeLibrary;
using System;
using System.Windows;
using IWshRuntimeLibrary;
using Application = System.Windows.Forms.Application;
using File = System.IO.File;
+3 -3
View File
@@ -1,8 +1,8 @@
using System;
using iNKORE.UI.WPF.Modern;
using Microsoft.Win32;
using System;
using System.Windows;
using System.Windows.Media;
using iNKORE.UI.WPF.Modern;
using Microsoft.Win32;
using Application = System.Windows.Application;
namespace Ink_Canvas
+2 -2
View File
@@ -1,4 +1,5 @@
using System;
using Ink_Canvas.Helpers;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading.Tasks;
@@ -6,7 +7,6 @@ using System.Windows;
using System.Windows.Controls;
using System.Windows.Ink;
using System.Windows.Media;
using Ink_Canvas.Helpers;
namespace Ink_Canvas
{
+2 -2
View File
@@ -1,4 +1,5 @@
using System;
using Ink_Canvas.Helpers;
using System;
using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;
@@ -6,7 +7,6 @@ using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using Ink_Canvas.Helpers;
namespace Ink_Canvas
{
@@ -1,4 +1,5 @@
using System;
using Ink_Canvas.Helpers;
using System;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
@@ -9,7 +10,6 @@ using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Threading;
using Ink_Canvas.Helpers;
using Clipboard = System.Windows.Clipboard;
using ContextMenu = System.Windows.Controls.ContextMenu;
using Cursors = System.Windows.Input.Cursors;
+2 -2
View File
@@ -1,4 +1,5 @@
using System;
using Ink_Canvas.Helpers;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Windows;
@@ -8,7 +9,6 @@ using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using Ink_Canvas.Helpers;
namespace Ink_Canvas
{
+17 -17
View File
@@ -1,4 +1,6 @@
using System;
using Ink_Canvas.Helpers;
using Microsoft.Win32;
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
@@ -10,8 +12,6 @@ using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Threading;
using Ink_Canvas.Helpers;
using Microsoft.Win32;
namespace Ink_Canvas
{
@@ -1229,23 +1229,23 @@ namespace Ink_Canvas
try
{
if (currentSelectedElement != null)
{
var elementCenter = new Point(currentSelectedElement.ActualWidth / 2, currentSelectedElement.ActualHeight / 2);
ApplyScaleTransform(currentSelectedElement, 1.1, elementCenter);
// 更新工具栏位置
if (currentSelectedElement is Image && BorderImageSelectionControl?.Visibility == Visibility.Visible)
{
UpdateImageSelectionToolbarPosition(currentSelectedElement);
}
var elementCenter = new Point(currentSelectedElement.ActualWidth / 2, currentSelectedElement.ActualHeight / 2);
ApplyScaleTransform(currentSelectedElement, 1.1, elementCenter);
LogHelper.WriteLogToFile("图片缩放增大完成");
// 更新工具栏位置
if (currentSelectedElement is Image && BorderImageSelectionControl?.Visibility == Visibility.Visible)
{
UpdateImageSelectionToolbarPosition(currentSelectedElement);
}
LogHelper.WriteLogToFile("图片缩放增大完成");
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"图片缩放增大失败: {ex.Message}", LogHelper.LogType.Error);
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"图片缩放增大失败: {ex.Message}", LogHelper.LogType.Error);
}
}
// 图片删除
+2 -2
View File
@@ -1,4 +1,5 @@
using System;
using Ink_Canvas.Helpers;
using System;
using System.Diagnostics;
using System.Linq;
using System.Windows;
@@ -6,7 +7,6 @@ using System.Windows.Controls;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using Ink_Canvas.Helpers;
namespace Ink_Canvas
{
@@ -1,3 +1,5 @@
using Ink_Canvas.Helpers;
using iNKORE.UI.WPF.Modern;
using System;
using System.Diagnostics;
using System.Threading;
@@ -11,8 +13,6 @@ using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using Ink_Canvas.Helpers;
using iNKORE.UI.WPF.Modern;
using Application = System.Windows.Application;
using Button = System.Windows.Controls.Button;
using Cursors = System.Windows.Input.Cursors;
@@ -893,7 +893,8 @@ namespace Ink_Canvas
HideSubPanels();
BtnSettings_Click(null, null);
}
private async void SymbolIconScreenshot_MouseUp(object sender, MouseButtonEventArgs e) {
private async void SymbolIconScreenshot_MouseUp(object sender, MouseButtonEventArgs e)
{
HideSubPanelsImmediately();
await Task.Delay(50);
SaveScreenShotToDesktop();
@@ -2044,7 +2045,7 @@ namespace Ink_Canvas
private void QuickColorOrange_Click(object sender, RoutedEventArgs e)
{
SetQuickColor(Color.FromRgb(251, 150, 80)); // 橙色
SetQuickColor(Color.FromRgb(251, 150, 80)); // 橙色
}
private void QuickColorYellow_Click(object sender, RoutedEventArgs e)
@@ -2067,7 +2068,7 @@ namespace Ink_Canvas
SetQuickColor(Colors.Red);
}
private void QuickColorGreen_Click(object sender, RoutedEventArgs e)
private void QuickColorGreen_Click(object sender, RoutedEventArgs e)
{
SetQuickColor(Color.FromRgb(22, 163, 74));
}
+1 -1
View File
@@ -1,3 +1,4 @@
using Ink_Canvas.Helpers;
using System;
using System.Collections.Generic;
using System.Drawing;
@@ -11,7 +12,6 @@ using System.Windows.Forms;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Threading;
using Ink_Canvas.Helpers;
using Application = System.Windows.Application;
using Color = System.Drawing.Color;
using Cursors = System.Windows.Input.Cursors;
+2 -2
View File
@@ -1,8 +1,8 @@
using System;
using Ink_Canvas.Helpers;
using System;
using System.Linq;
using System.Threading;
using System.Windows;
using Ink_Canvas.Helpers;
namespace Ink_Canvas
{
+5 -5
View File
@@ -1,4 +1,8 @@
using System;
using Ink_Canvas.Helpers;
using iNKORE.UI.WPF.Modern;
using Microsoft.Office.Core;
using Microsoft.Office.Interop.PowerPoint;
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
@@ -8,10 +12,6 @@ using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media;
using System.Windows.Threading;
using Ink_Canvas.Helpers;
using iNKORE.UI.WPF.Modern;
using Microsoft.Office.Core;
using Microsoft.Office.Interop.PowerPoint;
using Application = System.Windows.Application;
using File = System.IO.File;
using MessageBox = System.Windows.MessageBox;
+2 -2
View File
@@ -1,10 +1,10 @@
using System.Collections.ObjectModel;
using Ink_Canvas.Helpers;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Ink;
using System.Windows.Input;
using Ink_Canvas.Helpers;
namespace Ink_Canvas
{
@@ -1,3 +1,5 @@
using Ink_Canvas.Helpers;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Drawing;
@@ -12,8 +14,6 @@ using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using Ink_Canvas.Helpers;
using Newtonsoft.Json;
using Color = System.Drawing.Color;
using File = System.IO.File;
using Image = System.Windows.Controls.Image;
@@ -643,7 +643,7 @@ namespace Ink_Canvas
/// <summary>
/// 打开单个墨迹文件
/// </summary>
private void OpenSingleStrokeFile(string filePath)
public void OpenSingleStrokeFile(string filePath)
{
var fileStreamHasNoStroke = false;
using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
@@ -1,3 +1,4 @@
using iNKORE.UI.WPF.Modern.Controls;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -6,7 +7,6 @@ using System.Windows.Controls;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using iNKORE.UI.WPF.Modern.Controls;
using Point = System.Windows.Point;
namespace Ink_Canvas
+85 -5
View File
@@ -1,3 +1,7 @@
using Hardcodet.Wpf.TaskbarNotification;
using Ink_Canvas.Helpers;
using Newtonsoft.Json;
using OSVersionExtension;
using System;
using System.Diagnostics;
using System.IO;
@@ -10,10 +14,6 @@ using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Threading;
using Hardcodet.Wpf.TaskbarNotification;
using Ink_Canvas.Helpers;
using Newtonsoft.Json;
using OSVersionExtension;
using Application = System.Windows.Application;
using CheckBox = System.Windows.Controls.CheckBox;
using ComboBox = System.Windows.Controls.ComboBox;
@@ -2598,7 +2598,7 @@ namespace Ink_Canvas
if (Fold_Icon != null)
Fold_Icon.Visibility = Settings.Appearance.IsShowHideButton ? Visibility.Visible : Visibility.Collapsed;
// 快捷调色盘
// 快捷调色盘
if (QuickColorPalettePanel != null && QuickColorPaletteSingleRowPanel != null)
{
bool shouldShow = Settings.Appearance.IsShowQuickColorPalette && inkCanvas.EditingMode == InkCanvasEditingMode.Ink;
@@ -3080,5 +3080,85 @@ namespace Ink_Canvas
SaveSettingsToFile();
}
#region
private void BtnUnregisterFileAssociation_Click(object sender, RoutedEventArgs e)
{
try
{
bool success = FileAssociationManager.UnregisterFileAssociation();
if (success)
{
TextBlockFileAssociationStatus.Text = "✓ 文件关联已成功取消";
TextBlockFileAssociationStatus.Foreground = new SolidColorBrush(Colors.LightGreen);
ShowNotification("文件关联已取消");
}
else
{
TextBlockFileAssociationStatus.Text = "✗ 取消文件关联失败,可能需要管理员权限";
TextBlockFileAssociationStatus.Foreground = new SolidColorBrush(Colors.LightCoral);
ShowNotification("取消文件关联失败");
}
}
catch (Exception ex)
{
TextBlockFileAssociationStatus.Text = $"✗ 取消文件关联时出错: {ex.Message}";
TextBlockFileAssociationStatus.Foreground = new SolidColorBrush(Colors.LightCoral);
LogHelper.WriteLogToFile($"取消文件关联时出错: {ex.Message}", LogHelper.LogType.Error);
}
}
private void BtnCheckFileAssociation_Click(object sender, RoutedEventArgs e)
{
try
{
bool isRegistered = FileAssociationManager.IsFileAssociationRegistered();
if (isRegistered)
{
TextBlockFileAssociationStatus.Text = "✓ .icstk文件关联已注册";
TextBlockFileAssociationStatus.Foreground = new SolidColorBrush(Colors.LightGreen);
}
else
{
TextBlockFileAssociationStatus.Text = "✗ .icstk文件关联未注册";
TextBlockFileAssociationStatus.Foreground = new SolidColorBrush(Colors.LightCoral);
}
}
catch (Exception ex)
{
TextBlockFileAssociationStatus.Text = $"✗ 检查文件关联状态时出错: {ex.Message}";
TextBlockFileAssociationStatus.Foreground = new SolidColorBrush(Colors.LightCoral);
LogHelper.WriteLogToFile($"检查文件关联状态时出错: {ex.Message}", LogHelper.LogType.Error);
}
}
private void BtnRegisterFileAssociation_Click(object sender, RoutedEventArgs e)
{
try
{
bool success = FileAssociationManager.RegisterFileAssociation();
if (success)
{
TextBlockFileAssociationStatus.Text = "✓ 文件关联已成功注册";
TextBlockFileAssociationStatus.Foreground = new SolidColorBrush(Colors.LightGreen);
ShowNotification("文件关联已注册");
}
else
{
TextBlockFileAssociationStatus.Text = "✗ 注册文件关联失败,可能需要管理员权限";
TextBlockFileAssociationStatus.Foreground = new SolidColorBrush(Colors.LightCoral);
ShowNotification("注册文件关联失败");
}
}
catch (Exception ex)
{
TextBlockFileAssociationStatus.Text = $"✗ 注册文件关联时出错: {ex.Message}";
TextBlockFileAssociationStatus.Foreground = new SolidColorBrush(Colors.LightCoral);
LogHelper.WriteLogToFile($"注册文件关联时出错: {ex.Message}", LogHelper.LogType.Error);
}
}
#endregion
}
}
@@ -1,4 +1,8 @@
using System;
using Hardcodet.Wpf.TaskbarNotification;
using Ink_Canvas.Helpers;
using Newtonsoft.Json;
using OSVersionExtension;
using System;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
@@ -6,10 +10,6 @@ using System.Windows.Ink;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using Hardcodet.Wpf.TaskbarNotification;
using Ink_Canvas.Helpers;
using Newtonsoft.Json;
using OSVersionExtension;
using File = System.IO.File;
using OperatingSystem = OSVersionExtension.OperatingSystem;
+3 -3
View File
@@ -1,4 +1,6 @@
using System;
using Ink_Canvas.Helpers;
using iNKORE.UI.WPF.Modern.Controls;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading.Tasks;
@@ -8,8 +10,6 @@ using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using Ink_Canvas.Helpers;
using iNKORE.UI.WPF.Modern.Controls;
using MessageBox = System.Windows.MessageBox;
using Point = System.Windows.Point;
@@ -1,4 +1,5 @@
using System;
using Ink_Canvas.Helpers;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
@@ -8,7 +9,6 @@ using System.Windows.Controls;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using Ink_Canvas.Helpers;
using Point = System.Windows.Point;
namespace Ink_Canvas
+2 -2
View File
@@ -1,4 +1,5 @@
using System;
using Ink_Canvas.Helpers;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Windows;
@@ -6,7 +7,6 @@ using System.Windows.Controls;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using Ink_Canvas.Helpers;
namespace Ink_Canvas
{
+2 -2
View File
@@ -1,4 +1,5 @@
using System;
using Ink_Canvas.Helpers;
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
@@ -11,7 +12,6 @@ using System.Threading.Tasks;
using System.Timers;
using System.Windows;
using System.Windows.Controls;
using Ink_Canvas.Helpers;
namespace Ink_Canvas
{
+81 -81
View File
@@ -1,3 +1,4 @@
using Ink_Canvas.Helpers;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -8,7 +9,6 @@ using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Threading;
using Ink_Canvas.Helpers;
using Point = System.Windows.Point;
namespace Ink_Canvas
@@ -468,100 +468,100 @@ namespace Ink_Canvas
BlackboardUIGridForInkReplay.IsHitTestVisible = false;
dec.Add(e.TouchDevice.Id);
// Palm Eraser 逻辑 - 优化:改进手掌判定条件,提高精度
if (Settings.Canvas.EnablePalmEraser && dec.Count >= 2 && !isPalmEraserActive && !palmEraserTouchDownHandled)
{
var bounds = e.GetTouchPoint(inkCanvas).Bounds;
// 根据敏感度设置调整判定参数
double palmThreshold;
double aspectRatioThreshold;
int minTouchPoints;
switch (Settings.Canvas.PalmEraserSensitivity)
// Palm Eraser 逻辑 - 优化:改进手掌判定条件,提高精度
if (Settings.Canvas.EnablePalmEraser && dec.Count >= 2 && !isPalmEraserActive && !palmEraserTouchDownHandled)
{
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;
}
var bounds = e.GetTouchPoint(inkCanvas).Bounds;
// 计算宽高比
double aspectRatio = Math.Min(bounds.Width, bounds.Height) / Math.Max(bounds.Width, bounds.Height);
// 根据敏感度设置调整判定参数
double palmThreshold;
double aspectRatioThreshold;
int minTouchPoints;
// 更严格的手掌判定条件
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)
switch (Settings.Canvas.PalmEraserSensitivity)
{
palmEraserTouchIds.Add(touchId);
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;
}
// 切换为橡皮擦
EraserIcon_Click(null, null);
isPalmEraserActive = true;
palmEraserActivationTime = DateTime.Now; // 记录激活时间
palmEraserTouchDownHandled = true; // 标记已处理
// 计算宽高比
double aspectRatio = Math.Min(bounds.Width, bounds.Height) / Math.Max(bounds.Width, bounds.Height);
// 启动恢复定时器,防止卡死
StartPalmEraserRecoveryTimer();
// 更严格的手掌判定条件
bool isLargeTouch = bounds.Width >= palmThreshold && bounds.Height >= palmThreshold;
bool isPalmLikeShape = aspectRatio >= aspectRatioThreshold;
bool hasMultipleTouchPoints = dec.Count >= minTouchPoints;
// 记录日志
LogHelper.WriteLogToFile($"Palm eraser activated - Sensitivity: {Settings.Canvas.PalmEraserSensitivity}, Touch bounds: {bounds.Width}x{bounds.Height}, Aspect ratio: {aspectRatio:F2}, Touch points: {dec.Count}");
}
}
// 设备1个的时候,记录中心点
if (dec.Count == 1)
{
touchPoint = e.GetTouchPoint(inkCanvas);
centerPoint = touchPoint.Position;
// 修复:只允许在此处赋值iniP,防止TouchMove等其他地方覆盖,保证几何绘制起点一致
if (drawingShapeMode != 0)
{
// 对于双曲线绘制,第一笔时记录起点,第二笔时不更新起点
if (drawingShapeMode == 24 || drawingShapeMode == 25)
if (isLargeTouch && isPalmLikeShape && hasMultipleTouchPoints)
{
// 双曲线绘制:第一笔记录起点,第二笔保持第一笔的起点
if (drawMultiStepShapeCurrentStep == 0)
// 记录当前编辑模式和高光状态
palmEraserLastEditingMode = inkCanvas.EditingMode;
palmEraserLastIsHighlighter = drawingAttributes.IsHighlighter;
// 记录参与手掌擦的触摸点ID
palmEraserTouchIds.Clear();
foreach (int touchId in dec)
{
palmEraserTouchIds.Add(touchId);
}
// 切换为橡皮擦
EraserIcon_Click(null, null);
isPalmEraserActive = true;
palmEraserActivationTime = DateTime.Now; // 记录激活时间
palmEraserTouchDownHandled = true; // 标记已处理
// 启动恢复定时器,防止卡死
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}");
}
}
// 设备1个的时候,记录中心点
if (dec.Count == 1)
{
touchPoint = e.GetTouchPoint(inkCanvas);
centerPoint = touchPoint.Position;
// 修复:只允许在此处赋值iniP,防止TouchMove等其他地方覆盖,保证几何绘制起点一致
if (drawingShapeMode != 0)
{
// 对于双曲线绘制,第一笔时记录起点,第二笔时不更新起点
if (drawingShapeMode == 24 || drawingShapeMode == 25)
{
// 双曲线绘制:第一笔记录起点,第二笔保持第一笔的起点
if (drawMultiStepShapeCurrentStep == 0)
{
iniP = touchPoint.Position;
}
// 第二笔时不更新iniP,保持第一笔的起点
}
else
{
// 其他图形正常记录起点
iniP = touchPoint.Position;
}
// 第二笔时不更新iniP,保持第一笔的起点
}
else
{
// 其他图形正常记录起点
iniP = touchPoint.Position;
}
}
// 记录第一根手指点击时的 StrokeCollection
lastTouchDownStrokeCollection = inkCanvas.Strokes.Clone();
}
// 记录第一根手指点击时的 StrokeCollection
lastTouchDownStrokeCollection = inkCanvas.Strokes.Clone();
}
//设备两个及两个以上,将画笔功能关闭
if (dec.Count > 1 || isSingleFingerDragMode || !Settings.Gesture.IsEnableTwoFingerGesture)
{
+4 -4
View File
@@ -1,12 +1,12 @@
using System;
using Hardcodet.Wpf.TaskbarNotification;
using Ink_Canvas.Helpers;
using iNKORE.UI.WPF.Modern.Controls;
using System;
using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Forms;
using System.Windows.Interop;
using Hardcodet.Wpf.TaskbarNotification;
using Ink_Canvas.Helpers;
using iNKORE.UI.WPF.Modern.Controls;
using Application = System.Windows.Application;
using ContextMenu = System.Windows.Controls.ContextMenu;
using MenuItem = System.Windows.Controls.MenuItem;
+2 -2
View File
@@ -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.9.0")]
[assembly: AssemblyFileVersion("1.7.9.0")]
[assembly: AssemblyVersion("1.7.9.1")]
[assembly: AssemblyFileVersion("1.7.9.1")]
+2 -2
View File
@@ -1,7 +1,7 @@
using System;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using Newtonsoft.Json;
namespace Ink_Canvas
{
Binary file not shown.

Before

Width:  |  Height:  |  Size: 190 KiB

After

Width:  |  Height:  |  Size: 64 KiB

@@ -1,8 +1,8 @@
using Microsoft.Win32;
using System;
using System.IO;
using System.Windows;
using System.Windows.Media.Imaging;
using Microsoft.Win32;
namespace Ink_Canvas
{
@@ -1,8 +1,8 @@
using Microsoft.Win32;
using System;
using System.IO;
using System.Windows;
using System.Windows.Media.Imaging;
using Microsoft.Win32;
namespace Ink_Canvas
{
@@ -1,4 +1,5 @@
using System;
using Ink_Canvas.Helpers;
using System;
using System.ComponentModel;
using System.Media;
using System.Timers;
@@ -7,7 +8,6 @@ using System.Windows.Forms;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media;
using Ink_Canvas.Helpers;
using Application = System.Windows.Application;
using MouseEventArgs = System.Windows.Input.MouseEventArgs;
using Timer = System.Timers.Timer;
@@ -1,4 +1,7 @@
using System;
using Ink_Canvas.Helpers;
using iNKORE.UI.WPF.Modern.Controls;
using MdXaml;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
@@ -10,9 +13,6 @@ using System.Windows;
using System.Windows.Controls;
using System.Windows.Interop;
using System.Windows.Media;
using Ink_Canvas.Helpers;
using iNKORE.UI.WPF.Modern.Controls;
using MdXaml;
namespace Ink_Canvas
{
@@ -1,3 +1,4 @@
using Ink_Canvas.Helpers;
using System;
using System.Collections.Generic;
using System.ComponentModel;
@@ -7,7 +8,6 @@ using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using Ink_Canvas.Helpers;
// Added for OrderByDescending
@@ -1,10 +1,10 @@
using Ink_Canvas.Helpers;
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using Ink_Canvas.Helpers;
namespace Ink_Canvas.Windows
{
+2 -2
View File
@@ -1,7 +1,7 @@
using System.ComponentModel;
using Ink_Canvas.Helpers;
using System.ComponentModel;
using System.IO;
using System.Windows;
using Ink_Canvas.Helpers;
namespace Ink_Canvas
{
@@ -1,6 +1,6 @@
using System.Windows;
using Ink_Canvas.Helpers;
using System.Windows;
using System.Windows.Input;
using Ink_Canvas.Helpers;
namespace Ink_Canvas
{
@@ -1,3 +1,9 @@
using Ink_Canvas.Helpers;
using Ink_Canvas.Helpers.Plugins;
using Ink_Canvas.Helpers.Plugins.BuiltIn;
using Ink_Canvas.Helpers.Plugins.BuiltIn.SuperLauncher;
using iNKORE.UI.WPF.Modern.Controls;
using Microsoft.Win32;
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
@@ -6,12 +12,6 @@ using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Threading;
using Ink_Canvas.Helpers;
using Ink_Canvas.Helpers.Plugins;
using Ink_Canvas.Helpers.Plugins.BuiltIn;
using Ink_Canvas.Helpers.Plugins.BuiltIn.SuperLauncher;
using iNKORE.UI.WPF.Modern.Controls;
using Microsoft.Win32;
using MessageBox = System.Windows.MessageBox;
namespace Ink_Canvas.Windows
+3 -3
View File
@@ -1,4 +1,6 @@
using System;
using Ink_Canvas.Helpers;
using Microsoft.VisualBasic;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
@@ -8,8 +10,6 @@ using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using Ink_Canvas.Helpers;
using Microsoft.VisualBasic;
using MessageBox = iNKORE.UI.WPF.Modern.Controls.MessageBox;
namespace Ink_Canvas
@@ -43,8 +43,13 @@
<Rectangle Name="SelectionRectangle"
Stroke="White"
StrokeThickness="1"
Fill="Transparent"
Visibility="Collapsed" />
Fill="#01000000"
Visibility="Collapsed"
Panel.ZIndex="1001"
MouseLeftButtonDown="SelectionRectangle_MouseLeftButtonDown"
MouseLeftButtonUp="SelectionRectangle_MouseLeftButtonUp"
MouseMove="SelectionRectangle_MouseMove"
Cursor="SizeAll" />
<!-- 任意形状选择模式 -->
<Path Name="SelectionPath"
@@ -83,14 +88,14 @@
</Border>
</Canvas>
<!-- 部工具栏 -->
<!-- 部工具栏 -->
<Border Background="#1a1a1a"
Opacity="0.95"
CornerRadius="8"
Padding="12,8"
HorizontalAlignment="Center"
VerticalAlignment="Top"
Margin="0,20,0,0"
VerticalAlignment="Bottom"
Margin="0,0,0,80"
Panel.ZIndex="1000">
<StackPanel Orientation="Horizontal">
<!-- 模式切换按钮 -->
@@ -164,7 +169,7 @@
Padding="16,10"
HorizontalAlignment="Center"
VerticalAlignment="Bottom"
Margin="0,0,0,20"
Margin="0,0,0,140"
Visibility="Collapsed"
Panel.ZIndex="1000">
<TextBlock Text="拖拽控制点调整选择区域,或拖拽边框移动位置"
@@ -191,7 +191,8 @@ namespace Ink_Canvas
hitElement is Separator ||
hitElement.Name == "SizeInfoBorder" ||
hitElement.Name == "HintText" ||
hitElement.Name == "AdjustModeHint"))
hitElement.Name == "AdjustModeHint" ||
hitElement.Name == "SelectionRectangle"))
{
return;
}
@@ -243,6 +244,12 @@ namespace Ink_Canvas
private void Window_MouseMove(object sender, MouseEventArgs e)
{
// 如果正在调整模式且正在移动,不处理窗口级别的鼠标移动
if (_isAdjusting && _isMoving)
{
return;
}
if (_isSelecting)
{
_currentPoint = e.GetPosition(this);
@@ -266,6 +273,12 @@ namespace Ink_Canvas
private void Window_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
// 如果正在调整模式且正在移动,不处理窗口级别的鼠标释放
if (_isAdjusting && _isMoving)
{
return;
}
if (_isSelecting)
{
_isSelecting = false;
@@ -456,6 +469,12 @@ namespace Ink_Canvas
private void ShowControlPoints()
{
// 确保选择矩形在调整模式下可见
SelectionRectangle.Visibility = Visibility.Visible;
// 设置选择矩形的Z-index,确保它能够接收鼠标事件
WpfCanvas.SetZIndex(SelectionRectangle, 1001);
// 确保选择矩形能够接收鼠标事件
SelectionRectangle.IsHitTestVisible = true;
ControlPointsCanvas.Visibility = Visibility.Visible;
UpdateControlPointsPosition();
}
@@ -501,6 +520,12 @@ namespace Ink_Canvas
SelectionRectangle.Width = rect.Width;
SelectionRectangle.Height = rect.Height;
// 在选择过程中,禁用选择矩形的鼠标事件,避免干扰选择操作
if (_isSelecting)
{
SelectionRectangle.IsHitTestVisible = false;
}
// 更新透明选择区域遮罩
UpdateTransparentSelectionMask(rect);
@@ -527,7 +552,7 @@ namespace Ink_Canvas
TransparentSelectionMask.Visibility = Visibility.Visible;
OverlayRectangle.Visibility = Visibility.Collapsed;
}
catch (Exception ex)
catch (Exception)
{
// 如果几何体操作失败,回退到原始遮罩
TransparentSelectionMask.Visibility = Visibility.Collapsed;
@@ -545,6 +570,13 @@ namespace Ink_Canvas
SelectionRectangle.Width = rect.Width;
SelectionRectangle.Height = rect.Height;
// 确保选择矩形在调整模式下能够接收鼠标事件
if (_isAdjusting)
{
SelectionRectangle.IsHitTestVisible = true;
WpfCanvas.SetZIndex(SelectionRectangle, 1001);
}
// 更新透明选择区域遮罩
UpdateTransparentSelectionMask(rect);
@@ -694,6 +726,66 @@ namespace Ink_Canvas
return Math.Sqrt(dx * dx + dy * dy);
}
private void SelectionRectangle_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (!_isAdjusting) return;
_isMoving = true;
_activeControlPoint = ControlPointType.Move;
_lastMousePosition = e.GetPosition(this);
// 捕获鼠标到选择矩形
SelectionRectangle.CaptureMouse();
e.Handled = true;
}
private void SelectionRectangle_MouseMove(object sender, MouseEventArgs e)
{
if (!_isAdjusting || !_isMoving || _activeControlPoint != ControlPointType.Move) return;
try
{
var currentPosition = e.GetPosition(this);
var delta = currentPosition - _lastMousePosition;
// 移动整个选择区域
var newRect = _currentSelection;
newRect.X += delta.X;
newRect.Y += delta.Y;
// 确保选择区域不会移出屏幕边界
var screenBounds = new Rect(0, 0, ActualWidth, ActualHeight);
if (newRect.Left < 0) newRect.X = 0;
if (newRect.Top < 0) newRect.Y = 0;
if (newRect.Right > screenBounds.Right) newRect.X = screenBounds.Right - newRect.Width;
if (newRect.Bottom > screenBounds.Bottom) newRect.Y = screenBounds.Bottom - newRect.Height;
_currentSelection = newRect;
UpdateSelectionDisplay();
_lastMousePosition = currentPosition;
e.Handled = true;
}
catch (Exception)
{
// 如果出现异常,停止移动
_isMoving = false;
_activeControlPoint = ControlPointType.None;
SelectionRectangle.ReleaseMouseCapture();
}
}
private void SelectionRectangle_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
if (_isMoving && _activeControlPoint == ControlPointType.Move)
{
_isMoving = false;
_activeControlPoint = ControlPointType.None;
SelectionRectangle.ReleaseMouseCapture();
e.Handled = true;
}
}
private void ResetSelectionState()
{
// 重置所有选择相关的状态
@@ -709,6 +801,7 @@ namespace Ink_Canvas
// 清除矩形选择的内容
SelectionRectangle.Visibility = Visibility.Collapsed;
SelectionRectangle.IsHitTestVisible = false;
ControlPointsCanvas.Visibility = Visibility.Collapsed;
SizeInfoBorder.Visibility = Visibility.Collapsed;
SelectionPath.Visibility = Visibility.Collapsed;
@@ -724,6 +817,12 @@ namespace Ink_Canvas
ReleaseMouseCapture();
}
// 释放选择矩形的鼠标捕获
if (SelectionRectangle.IsMouseCaptured)
{
SelectionRectangle.ReleaseMouseCapture();
}
// 重置选择区域
_currentSelection = new Rect();
SelectedArea = null;
@@ -6,7 +6,7 @@
xmlns:local="clr-namespace:Ink_Canvas" xmlns:ui="http://schemas.inkore.net/lib/ui/wpf/modern"
mc:Ignorable="d" Topmost="True" WindowStartupLocation="CenterScreen" ui:WindowHelper.UseModernWindowStyle="True"
ResizeMode="NoResize" Closed="Window_Closed" ui:ThemeManager.RequestedTheme="Light"
Title="演示文档设置 - Ink Canvas 画板" Height="160" Width="450" FontFamily="Microsoft YaHei UI">
Title="演示文档设置 - Ink Canvas For Class CE" Height="160" Width="450" FontFamily="Microsoft YaHei UI">
<Grid>
<Grid Margin="10">
<Grid.RowDefinitions>