improve:issue #112
This commit is contained in:
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user