improve:issue #112

This commit is contained in:
2025-08-23 21:39:00 +08:00
parent 108c6b2b17
commit 710a9014dd
13 changed files with 1414 additions and 19 deletions
+301
View File
@@ -0,0 +1,301 @@
using System;
using System.Collections.Generic;
using System.Windows.Input;
using NHotkey.Wpf;
namespace Ink_Canvas.Helpers
{
/// <summary>
/// 全局快捷键管理器 - 使用NHotkey库实现全局快捷键功能
/// </summary>
public class GlobalHotkeyManager : IDisposable
{
#region Private Fields
private readonly Dictionary<string, HotkeyInfo> _registeredHotkeys;
private readonly MainWindow _mainWindow;
private bool _isDisposed = false;
#endregion
#region Constructor
public GlobalHotkeyManager(MainWindow mainWindow)
{
_mainWindow = mainWindow ?? throw new ArgumentNullException(nameof(mainWindow));
_registeredHotkeys = new Dictionary<string, HotkeyInfo>();
}
#endregion
#region Public Methods
/// <summary>
/// 注册全局快捷键
/// </summary>
/// <param name="hotkeyName">快捷键名称</param>
/// <param name="key">按键</param>
/// <param name="modifiers">修饰键</param>
/// <param name="action">执行动作</param>
/// <returns>是否注册成功</returns>
public bool RegisterHotkey(string hotkeyName, Key key, ModifierKeys modifiers, Action action)
{
try
{
if (_isDisposed)
return false;
// 如果快捷键已存在,先注销
if (_registeredHotkeys.ContainsKey(hotkeyName))
{
UnregisterHotkey(hotkeyName);
}
// 创建快捷键信息
var hotkeyInfo = new HotkeyInfo
{
Name = hotkeyName,
Key = key,
Modifiers = modifiers,
Action = action
};
// 注册快捷键
HotkeyManager.Current.AddOrReplace(hotkeyName, key, modifiers, (sender, e) =>
{
try
{
// 确保在主线程中执行
_mainWindow.Dispatcher.Invoke(() =>
{
action?.Invoke();
});
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"执行快捷键 {hotkeyName} 时出错: {ex.Message}", LogHelper.LogType.Error);
}
});
_registeredHotkeys[hotkeyName] = hotkeyInfo;
LogHelper.WriteLogToFile($"成功注册全局快捷键: {hotkeyName} ({modifiers}+{key})", LogHelper.LogType.Event);
return true;
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"注册全局快捷键 {hotkeyName} 失败: {ex.Message}", LogHelper.LogType.Error);
return false;
}
}
/// <summary>
/// 注销指定快捷键
/// </summary>
/// <param name="hotkeyName">快捷键名称</param>
/// <returns>是否注销成功</returns>
public bool UnregisterHotkey(string hotkeyName)
{
try
{
if (_isDisposed || !_registeredHotkeys.ContainsKey(hotkeyName))
return false;
HotkeyManager.Current.Remove(hotkeyName);
_registeredHotkeys.Remove(hotkeyName);
LogHelper.WriteLogToFile($"成功注销全局快捷键: {hotkeyName}", LogHelper.LogType.Event);
return true;
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"注销全局快捷键 {hotkeyName} 失败: {ex.Message}", LogHelper.LogType.Error);
return false;
}
}
/// <summary>
/// 注销所有快捷键
/// </summary>
public void UnregisterAllHotkeys()
{
try
{
if (_isDisposed)
return;
foreach (var hotkeyName in _registeredHotkeys.Keys)
{
try
{
HotkeyManager.Current.Remove(hotkeyName);
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"注销快捷键 {hotkeyName} 时出错: {ex.Message}", LogHelper.LogType.Warning);
}
}
_registeredHotkeys.Clear();
LogHelper.WriteLogToFile("已注销所有全局快捷键", LogHelper.LogType.Event);
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"注销所有快捷键时出错: {ex.Message}", LogHelper.LogType.Error);
}
}
/// <summary>
/// 检查快捷键是否已注册
/// </summary>
/// <param name="hotkeyName">快捷键名称</param>
/// <returns>是否已注册</returns>
public bool IsHotkeyRegistered(string hotkeyName)
{
return _registeredHotkeys.ContainsKey(hotkeyName);
}
/// <summary>
/// 获取已注册的快捷键列表
/// </summary>
/// <returns>快捷键信息列表</returns>
public List<HotkeyInfo> GetRegisteredHotkeys()
{
return new List<HotkeyInfo>(_registeredHotkeys.Values);
}
/// <summary>
/// 注册默认快捷键集合
/// </summary>
public void RegisterDefaultHotkeys()
{
try
{
// 基本操作快捷键
RegisterHotkey("Undo", Key.Z, ModifierKeys.Control, () => _mainWindow.SymbolIconUndo_MouseUp(null, null));
RegisterHotkey("Redo", Key.Y, ModifierKeys.Control, () => _mainWindow.SymbolIconRedo_MouseUp(null, null));
RegisterHotkey("Clear", Key.E, ModifierKeys.Control, () => _mainWindow.SymbolIconDelete_MouseUp(null, null));
RegisterHotkey("Paste", Key.V, ModifierKeys.Control, () => _mainWindow.HandleGlobalPaste(null, null));
// 工具切换快捷键
RegisterHotkey("SelectTool", Key.S, ModifierKeys.Alt, () => _mainWindow.SymbolIconSelect_MouseUp(null, null));
RegisterHotkey("DrawTool", Key.D, ModifierKeys.Alt, () => _mainWindow.PenIcon_Click(null, null));
RegisterHotkey("EraserTool", Key.E, ModifierKeys.Alt, () => _mainWindow.EraserIcon_Click(null, null));
RegisterHotkey("BlackboardTool", Key.B, ModifierKeys.Alt, () => _mainWindow.ImageBlackboard_MouseUp(null, null));
RegisterHotkey("QuitDrawTool", Key.Q, ModifierKeys.Alt, () => _mainWindow.CursorIcon_Click(null, null));
// 画笔快捷键 - 使用反射访问penType字段
RegisterHotkey("Pen1", Key.D1, ModifierKeys.Alt, () => SwitchToPenType(0));
RegisterHotkey("Pen2", Key.D2, ModifierKeys.Alt, () => SwitchToPenType(1));
RegisterHotkey("Pen3", Key.D3, ModifierKeys.Alt, () => SwitchToPenType(2));
RegisterHotkey("Pen4", Key.D4, ModifierKeys.Alt, () => SwitchToPenType(3));
RegisterHotkey("Pen5", Key.D5, ModifierKeys.Alt, () => SwitchToPenType(4));
// 功能快捷键
RegisterHotkey("DrawLine", Key.L, ModifierKeys.Alt, () => _mainWindow.BtnDrawLine_Click(null, null));
RegisterHotkey("Screenshot", Key.C, ModifierKeys.Alt, () => _mainWindow.SaveScreenShotToDesktop());
RegisterHotkey("Hide", Key.V, ModifierKeys.Alt, () => _mainWindow.SymbolIconEmoji_MouseUp(null, null));
// 退出快捷键
RegisterHotkey("Exit", Key.Escape, ModifierKeys.None, () => _mainWindow.KeyExit(null, null));
LogHelper.WriteLogToFile("已注册默认全局快捷键集合", LogHelper.LogType.Event);
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"注册默认快捷键时出错: {ex.Message}", LogHelper.LogType.Error);
}
}
/// <summary>
/// 从设置加载快捷键配置
/// </summary>
public void LoadHotkeysFromSettings()
{
try
{
// 这里可以从配置文件或设置中加载自定义快捷键
// 暂时使用默认快捷键
RegisterDefaultHotkeys();
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"从设置加载快捷键时出错: {ex.Message}", LogHelper.LogType.Error);
}
}
/// <summary>
/// 保存快捷键配置到设置
/// </summary>
public void SaveHotkeysToSettings()
{
try
{
// 这里可以将快捷键配置保存到配置文件或设置中
LogHelper.WriteLogToFile("快捷键配置已保存", LogHelper.LogType.Event);
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"保存快捷键配置时出错: {ex.Message}", LogHelper.LogType.Error);
}
}
#endregion
#region Private Helper Methods
/// <summary>
/// 切换到指定笔类型
/// </summary>
/// <param name="penTypeIndex">笔类型索引</param>
private void SwitchToPenType(int penTypeIndex)
{
try
{
// 通过反射访问主窗口的penType字段
var penTypeField = _mainWindow.GetType().GetField("penType",
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
if (penTypeField != null)
{
penTypeField.SetValue(_mainWindow, penTypeIndex);
// 调用CheckPenTypeUIState方法更新UI状态
var checkPenTypeMethod = _mainWindow.GetType().GetMethod("CheckPenTypeUIState",
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
if (checkPenTypeMethod != null)
{
checkPenTypeMethod.Invoke(_mainWindow, null);
}
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"切换到笔类型{penTypeIndex}时出错: {ex.Message}", LogHelper.LogType.Error);
}
}
#endregion
#region IDisposable Implementation
public void Dispose()
{
if (!_isDisposed)
{
UnregisterAllHotkeys();
_isDisposed = true;
}
}
#endregion
#region Nested Classes
/// <summary>
/// 快捷键信息类
/// </summary>
public class HotkeyInfo
{
public string Name { get; set; }
public Key Key { get; set; }
public ModifierKeys Modifiers { get; set; }
public Action Action { get; set; }
public override string ToString()
{
var modifiersText = Modifiers == ModifierKeys.None ? "" : $"{Modifiers}+";
return $"{modifiersText}{Key}";
}
}
#endregion
}
}
+264
View File
@@ -0,0 +1,264 @@
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Media.Animation;
using System.Windows.Threading;
using System.Windows.Ink;
namespace Ink_Canvas.Helpers
{
/// <summary>
/// 墨迹渐隐管理器 - 管理墨迹的渐隐动画和状态
/// </summary>
public class InkFadeManager
{
#region Properties
/// <summary>
/// 是否启用墨迹渐隐功能
/// </summary>
public bool IsEnabled { get; set; } = false;
/// <summary>
/// 墨迹渐隐时间(毫秒)
/// </summary>
public int FadeTime { get; set; } = 3000;
/// <summary>
/// 渐隐动画持续时间(毫秒)
/// </summary>
public int AnimationDuration { get; set; } = 1000;
#endregion
#region Private Fields
private readonly MainWindow _mainWindow;
private readonly Dispatcher _dispatcher;
private readonly Dictionary<Stroke, DispatcherTimer> _fadeTimers;
private readonly Dictionary<Stroke, UIElement> _strokeVisuals;
#endregion
#region Constructor
public InkFadeManager(MainWindow mainWindow)
{
_mainWindow = mainWindow ?? throw new ArgumentNullException(nameof(mainWindow));
_dispatcher = _mainWindow.Dispatcher;
_fadeTimers = new Dictionary<Stroke, DispatcherTimer>();
_strokeVisuals = new Dictionary<Stroke, UIElement>();
}
#endregion
#region Public Methods
/// <summary>
/// 添加需要渐隐的墨迹
/// </summary>
/// <param name="stroke">墨迹对象</param>
/// <param name="visual">墨迹的视觉元素</param>
public void AddFadingStroke(Stroke stroke, UIElement visual)
{
if (!IsEnabled || stroke == null || visual == null) return;
try
{
// 记录墨迹和视觉元素的对应关系
_strokeVisuals[stroke] = visual;
// 创建定时器,在指定时间后开始渐隐动画
var timer = new DispatcherTimer
{
Interval = TimeSpan.FromMilliseconds(FadeTime)
};
timer.Tick += (sender, e) =>
{
StartFadeAnimation(stroke);
timer.Stop();
_fadeTimers.Remove(stroke);
};
_fadeTimers[stroke] = timer;
timer.Start();
// 将视觉元素添加到画布上
_dispatcher.InvokeAsync(() =>
{
try
{
if (_mainWindow.inkCanvas != null)
{
_mainWindow.inkCanvas.Children.Add(visual);
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"添加墨迹视觉元素到画布失败: {ex}", LogHelper.LogType.Error);
}
});
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"添加渐隐墨迹失败: {ex}", LogHelper.LogType.Error);
}
}
/// <summary>
/// 移除墨迹
/// </summary>
/// <param name="stroke">要移除的墨迹</param>
public void RemoveStroke(Stroke stroke)
{
if (stroke == null) return;
try
{
if (_fadeTimers.TryGetValue(stroke, out var timer))
{
timer.Stop();
_fadeTimers.Remove(stroke);
}
if (_strokeVisuals.TryGetValue(stroke, out var visual))
{
_dispatcher.InvokeAsync(() =>
{
try
{
if (_mainWindow.inkCanvas != null && _mainWindow.inkCanvas.Children.Contains(visual))
{
_mainWindow.inkCanvas.Children.Remove(visual);
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"从画布移除墨迹视觉元素失败: {ex}", LogHelper.LogType.Error);
}
});
_strokeVisuals.Remove(stroke);
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"移除渐隐墨迹失败: {ex}", LogHelper.LogType.Error);
}
}
/// <summary>
/// 清除所有渐隐墨迹
/// </summary>
public void ClearAllFadingStrokes()
{
try
{
foreach (var timer in _fadeTimers.Values)
{
timer.Stop();
}
_fadeTimers.Clear();
_dispatcher.InvokeAsync(() =>
{
try
{
if (_mainWindow.inkCanvas != null)
{
foreach (var visual in _strokeVisuals.Values)
{
if (_mainWindow.inkCanvas.Children.Contains(visual))
{
_mainWindow.inkCanvas.Children.Remove(visual);
}
}
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"清除所有墨迹视觉元素失败: {ex}", LogHelper.LogType.Error);
}
});
_strokeVisuals.Clear();
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"清除所有渐隐墨迹失败: {ex}", LogHelper.LogType.Error);
}
}
/// <summary>
/// 更新渐隐时间设置
/// </summary>
/// <param name="fadeTime">新的渐隐时间(毫秒)</param>
public void UpdateFadeTime(int fadeTime)
{
FadeTime = fadeTime;
foreach (var kvp in _fadeTimers)
{
var stroke = kvp.Key;
var timer = kvp.Value;
timer.Stop();
timer.Interval = TimeSpan.FromMilliseconds(FadeTime);
timer.Start();
}
}
/// <summary>
/// 更新动画持续时间设置
/// </summary>
/// <param name="animationDuration">新的动画持续时间(毫秒)</param>
public void UpdateAnimationDuration(int animationDuration)
{
AnimationDuration = animationDuration;
}
#endregion
#region Private Methods
/// <summary>
/// 开始渐隐动画
/// </summary>
/// <param name="stroke">要渐隐的墨迹</param>
private void StartFadeAnimation(Stroke stroke)
{
if (!_strokeVisuals.TryGetValue(stroke, out var visual)) return;
try
{
_dispatcher.InvokeAsync(() =>
{
var fadeAnimation = new DoubleAnimation
{
From = 1.0,
To = 0.0,
Duration = TimeSpan.FromMilliseconds(AnimationDuration),
EasingFunction = new CubicEase { EasingMode = EasingMode.EaseInOut }
};
fadeAnimation.Completed += (sender, e) =>
{
try
{
if (_mainWindow.inkCanvas != null && _mainWindow.inkCanvas.Children.Contains(visual))
{
_mainWindow.inkCanvas.Children.Remove(visual);
}
RemoveStroke(stroke);
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"渐隐动画完成后清理墨迹失败: {ex}", LogHelper.LogType.Error);
}
};
visual.BeginAnimation(UIElement.OpacityProperty, fadeAnimation);
});
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"开始渐隐动画失败: {ex}", LogHelper.LogType.Error);
}
}
#endregion
}
}
-1
View File
@@ -3,7 +3,6 @@ using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Threading;
using Ink_Canvas.Helpers;
namespace Ink_Canvas.Helpers
{