You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

154 lines
5.7 KiB

using System.Collections.Concurrent;
using System.Diagnostics;
using EnumsNET;
using GlobalHotKey;
using log4net;
using SparkClient.Model.Extension;
namespace SparkClient.Model.Helper;
public sealed class ClientHotKeyManager
{
private static readonly ILog Logger = LogManager.GetLogger(typeof(ClientHotKeyManager));
#region 单例模式
private static readonly Lazy<ClientHotKeyManager> _instance =
new Lazy<ClientHotKeyManager>(() => new ClientHotKeyManager());
public static ClientHotKeyManager Instance => _instance.Value;
private ClientHotKeyManager() { }
#endregion
#region 存储结构
private readonly ConcurrentDictionary<HotKey, HotKeyRecord> _hotKeys =
new ConcurrentDictionary<HotKey, HotKeyRecord>();
private readonly ConcurrentDictionary<HotKey, HotKeyManager> _manager =
new ConcurrentDictionary<HotKey, HotKeyManager>();
// private HotKeyManager _hotKeyManager = new HotKeyManager();
#endregion
#region 公共方法
/// <summary>
/// 注册热键
/// </summary>
/// <param name="hotKey">热键</param>
/// <param name="handler">事件</param>
/// <param name="registrant">来源类</param>
/// <exception cref="ArgumentNullException">非法参数</exception>
/// <exception cref="InvalidOperationException">重复注册</exception>
public void Register(HotKey hotKey, EventHandler<KeyPressedEventArgs> handler, object registrant = null)
{
if (hotKey == null) throw new ArgumentNullException(nameof(hotKey));
if (handler == null) throw new ArgumentNullException(nameof(handler));
Logger.Info($"快捷键注册: [ Key = {hotKey.Key.GetName()}, Modifiers = {hotKey.Modifiers.ToSafeAbundantString()}, Handler = {handler.Method.Name}, From = {registrant.GetType().Name}]");
var record = new HotKeyRecord(hotKey, handler, registrant ?? GetDefaultRegistrant());
if (_hotKeys.TryAdd(hotKey, record))
{
HotKeyManager _hotKeyManager = new HotKeyManager();
_hotKeyManager.Register(hotKey);
_hotKeyManager.KeyPressed += handler;
_manager.TryAdd(hotKey, _hotKeyManager);
}
else
{
Logger.Info($"快捷键注册跳过: [ Key = {hotKey.Key.GetName()}, Modifiers = {hotKey.Modifiers.ToSafeAbundantString()}, Handler = {handler.Method.Name}, From = {registrant.GetType().Name}]");
return;
}
}
/// <summary>
/// 释放热键
/// </summary>
/// <param name="hotKey"></param>
public void Unregister(HotKey hotKey)
{
if (_hotKeys.TryRemove(hotKey, out var record))
{
Logger.Info($"快捷键释放: {hotKey.ToSafeAbundantString()}");
HotKeyManager _hotKeyManager = _manager.ContainsKey(hotKey)? _manager[hotKey]: new HotKeyManager();
_hotKeyManager.Unregister(hotKey);
_hotKeyManager.KeyPressed -= record.Handler;
_manager.TryRemove(hotKey, out _);
}
}
/// <summary>
/// 热键是否注册
/// </summary>
/// <param name="hotKey"></param>
/// <returns></returns>
public bool ContainsHotKey(HotKey hotKey) => _hotKeys.ContainsKey(hotKey);
/// <summary>
/// 刷新热键
/// </summary>
/// <param name="hotKey"></param>
/// <param name="newHandler"></param>
/// <param name="newRegistrant"></param>
/// <exception cref="ArgumentNullException"></exception>
private void RefreshHotKey(HotKey hotKey, EventHandler<KeyPressedEventArgs> newHandler, object newRegistrant = null)
{
if (hotKey == null || newHandler == null) throw new ArgumentNullException();
var registrant = newRegistrant ?? GetDefaultRegistrant();
if (!_manager.ContainsKey(hotKey))
{
HotKeyManager managerTemp = new HotKeyManager();
managerTemp.Register(hotKey);
managerTemp.KeyPressed += newHandler;
_manager.TryAdd(hotKey, managerTemp);
}
HotKeyManager _hotKeyManager = _manager.ContainsKey(hotKey)? _manager[hotKey]: null;
_hotKeys.AddOrUpdate(
hotKey,
key =>
{
_hotKeyManager.Register(key);
_hotKeyManager.KeyPressed += newHandler;
return new HotKeyRecord(hotKey, newHandler,newRegistrant);
},
(key, existingRecord) =>
{
_hotKeyManager.KeyPressed -= existingRecord.Handler;
_hotKeyManager.KeyPressed += newHandler;
return new HotKeyRecord(hotKey, newHandler,newRegistrant);
});
}
#endregion
#region 调试支持
[Conditional("DEBUG")]
public void PrintDebugInfo()
{
foreach (var kvp in _hotKeys)
{
Debug.WriteLine($"HotKey: {kvp.Key} | Registrant: {kvp.Value.Registrant}");
}
}
#endregion
#region 辅助方法
private object GetDefaultRegistrant()
{
// 获取调用堆栈中的注册者信息(例如:类名+方法名)
var stackTrace = new StackTrace(skipFrames: 2);
var frame = stackTrace.GetFrame(0);
return $"{frame.GetMethod().DeclaringType?.Name}.{frame.GetMethod().Name}";
}
#endregion
#region 内部记录类
private class HotKeyRecord
{
public HotKey HotKey { get; }
public EventHandler<KeyPressedEventArgs> Handler { get; }
public object Registrant { get; }
public HotKeyRecord(HotKey hotKey, EventHandler<KeyPressedEventArgs> handler, object registrant)
{
HotKey = hotKey;
Handler = handler;
Registrant = registrant;
}
}
#endregion
}