feat: 引入 CloudSync 核心能力并新增 Avalonia 桌面端与发布脚本
- 后端:新增 CloudSync 认证/权限/端点/服务与 DTO - 数据:新增用户/会话/安全策略实体与 EF Core migrations - 前端:新增云同步设置 UI、客户端与本地存储;Vite 支持 maui 构建输出到 wwwroot - 桌面端:新增 Avalonia 项目、内置 WebServer、托盘与 Windows 全局热键 - 发布/构建:新增 Windows/Linux 发布脚本与统一入口;调整 MAUI 资源与安装包配置 - 文档:同步更新 README/docs 与协作规则
This commit is contained in:
@@ -0,0 +1,138 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Hua.Todo.Avalonia.Services.Platforms;
|
||||
|
||||
/// <summary>
|
||||
/// Windows 全局键盘事件处理器。
|
||||
/// 用于监听按键并向上层暴露事件(例如 Esc),以保证在 WebView 获得焦点时依旧可触发窗口级交互。
|
||||
/// </summary>
|
||||
public sealed class WindowsKeyboardHandler : IDisposable
|
||||
{
|
||||
private readonly KeyboardHook _keyboardHook;
|
||||
private bool _isDisposed;
|
||||
|
||||
/// <summary>
|
||||
/// 当检测到 Esc 键抬起时触发。
|
||||
/// </summary>
|
||||
public event EventHandler? EscKeyPressed;
|
||||
|
||||
/// <summary>
|
||||
/// 创建 <see cref="WindowsKeyboardHandler"/>。
|
||||
/// </summary>
|
||||
public WindowsKeyboardHandler()
|
||||
{
|
||||
_keyboardHook = new KeyboardHook();
|
||||
_keyboardHook.KeyPressed += OnKeyPressed;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 开始监听键盘事件。
|
||||
/// </summary>
|
||||
public void Start()
|
||||
{
|
||||
_keyboardHook.Hook();
|
||||
}
|
||||
|
||||
private void OnKeyPressed(object? sender, KeyPressedEventArgs e)
|
||||
{
|
||||
if (e.Key == 0x1B && !e.IsKeyDown)
|
||||
{
|
||||
EscKeyPressed?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Dispose()
|
||||
{
|
||||
if (_isDisposed) return;
|
||||
_isDisposed = true;
|
||||
|
||||
_keyboardHook.Unhook();
|
||||
_keyboardHook.KeyPressed -= OnKeyPressed;
|
||||
}
|
||||
|
||||
private sealed class KeyboardHook : IDisposable
|
||||
{
|
||||
private const int WhKeyboardLl = 13;
|
||||
private const int WmKeyDown = 0x0100;
|
||||
private const int WmKeyUp = 0x0101;
|
||||
private const int WmSysKeyDown = 0x0104;
|
||||
private const int WmSysKeyUp = 0x0105;
|
||||
|
||||
private readonly LowLevelKeyboardProc _proc;
|
||||
private IntPtr _hookId = IntPtr.Zero;
|
||||
private bool _isDisposed;
|
||||
|
||||
public event EventHandler<KeyPressedEventArgs>? KeyPressed;
|
||||
|
||||
public KeyboardHook()
|
||||
{
|
||||
_proc = HookCallback;
|
||||
}
|
||||
|
||||
public void Hook()
|
||||
{
|
||||
if (_hookId != IntPtr.Zero) return;
|
||||
_hookId = SetWindowsHookEx(WhKeyboardLl, _proc, GetModuleHandle(null), 0);
|
||||
}
|
||||
|
||||
public void Unhook()
|
||||
{
|
||||
if (_hookId == IntPtr.Zero) return;
|
||||
UnhookWindowsHookEx(_hookId);
|
||||
_hookId = IntPtr.Zero;
|
||||
}
|
||||
|
||||
private IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
|
||||
{
|
||||
if (nCode >= 0)
|
||||
{
|
||||
var vkCode = Marshal.ReadInt32(lParam);
|
||||
var isKeyDown = wParam == (IntPtr)WmKeyDown || wParam == (IntPtr)WmSysKeyDown;
|
||||
var isKeyUp = wParam == (IntPtr)WmKeyUp || wParam == (IntPtr)WmSysKeyUp;
|
||||
|
||||
if (isKeyDown || isKeyUp)
|
||||
{
|
||||
KeyPressed?.Invoke(this, new KeyPressedEventArgs(vkCode, isKeyDown));
|
||||
}
|
||||
}
|
||||
|
||||
return CallNextHookEx(_hookId, nCode, wParam, lParam);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_isDisposed) return;
|
||||
_isDisposed = true;
|
||||
Unhook();
|
||||
}
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||
private static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||
private static extern bool UnhookWindowsHookEx(IntPtr hhk);
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
|
||||
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||
private static extern IntPtr GetModuleHandle(string? lpModuleName);
|
||||
}
|
||||
|
||||
private delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);
|
||||
|
||||
private sealed class KeyPressedEventArgs : EventArgs
|
||||
{
|
||||
public int Key { get; }
|
||||
public bool IsKeyDown { get; }
|
||||
|
||||
public KeyPressedEventArgs(int key, bool isKeyDown)
|
||||
{
|
||||
Key = key;
|
||||
IsKeyDown = isKeyDown;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user