ceb77e624e
feat: 重构 TodoList 架构,新增动态 API 与 MAUI 内嵌 Web 服务 feat:优化交互逻辑,优化发布流程
129 lines
3.8 KiB
C#
129 lines
3.8 KiB
C#
using System.Runtime.InteropServices;
|
|
|
|
namespace TodoList.Maui.Platforms.Windows
|
|
{
|
|
public class WindowsKeyboardHandler : IDisposable
|
|
{
|
|
private KeyboardHook _keyboardHook;
|
|
private bool _isDisposed;
|
|
|
|
public event EventHandler? EscKeyPressed;
|
|
|
|
public WindowsKeyboardHandler()
|
|
{
|
|
_keyboardHook = new KeyboardHook();
|
|
_keyboardHook.KeyPressed += OnKeyPressed;
|
|
}
|
|
|
|
public void Start()
|
|
{
|
|
_keyboardHook.Hook();
|
|
}
|
|
|
|
private void OnKeyPressed(object? sender, KeyPressedEventArgs e)
|
|
{
|
|
if (e.Key == 0x1B && !e.IsKeyDown)
|
|
{
|
|
EscKeyPressed?.Invoke(this, EventArgs.Empty);
|
|
}
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
if (!_isDisposed)
|
|
{
|
|
_keyboardHook.Unhook();
|
|
_keyboardHook.KeyPressed -= OnKeyPressed;
|
|
_isDisposed = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
internal class KeyboardHook : IDisposable
|
|
{
|
|
private const int WH_KEYBOARD_LL = 13;
|
|
private const int WM_KEYDOWN = 0x0100;
|
|
private const int WM_KEYUP = 0x0101;
|
|
private const int WM_SYSKEYDOWN = 0x0104;
|
|
private const int WM_SYSKEYUP = 0x0105;
|
|
|
|
private IntPtr _hookID = IntPtr.Zero;
|
|
private LowLevelKeyboardProc _proc;
|
|
private bool _isDisposed;
|
|
|
|
public event EventHandler<KeyPressedEventArgs>? KeyPressed;
|
|
|
|
public KeyboardHook()
|
|
{
|
|
_proc = HookCallback;
|
|
}
|
|
|
|
public void Hook()
|
|
{
|
|
_hookID = SetWindowsHookEx(WH_KEYBOARD_LL, _proc, GetModuleHandle("user32"), 0);
|
|
}
|
|
|
|
public void Unhook()
|
|
{
|
|
if (_hookID != IntPtr.Zero)
|
|
{
|
|
UnhookWindowsHookEx(_hookID);
|
|
_hookID = IntPtr.Zero;
|
|
}
|
|
}
|
|
|
|
private IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
|
|
{
|
|
if (nCode >= 0)
|
|
{
|
|
int vkCode = Marshal.ReadInt32(lParam);
|
|
bool isKeyDown = wParam == (IntPtr)WM_KEYDOWN || wParam == (IntPtr)WM_SYSKEYDOWN;
|
|
bool isKeyUp = wParam == (IntPtr)WM_KEYUP || wParam == (IntPtr)WM_SYSKEYUP;
|
|
|
|
if (isKeyDown || isKeyUp)
|
|
{
|
|
var args = new KeyPressedEventArgs(vkCode, isKeyDown);
|
|
KeyPressed?.Invoke(this, args);
|
|
}
|
|
}
|
|
|
|
return CallNextHookEx(_hookID, nCode, wParam, lParam);
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
if (!_isDisposed)
|
|
{
|
|
Unhook();
|
|
_isDisposed = true;
|
|
}
|
|
}
|
|
|
|
[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)]
|
|
[return: MarshalAs(UnmanagedType.Bool)]
|
|
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);
|
|
}
|
|
|
|
internal delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);
|
|
|
|
internal class KeyPressedEventArgs : EventArgs
|
|
{
|
|
public int Key { get; }
|
|
public bool IsKeyDown { get; }
|
|
|
|
public KeyPressedEventArgs(int key, bool isKeyDown)
|
|
{
|
|
Key = key;
|
|
IsKeyDown = isKeyDown;
|
|
}
|
|
}
|
|
} |