dot/src/Native/KeyboardHook.cs
2022-12-21 11:08:03 +08:00

72 lines
1.7 KiB
C#

// ReSharper disable ClassNeverInstantiated.Global
#if NET7_0_WINDOWS
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace Dot.Native;
internal sealed class KeyboardHook : IDisposable
{
private readonly nint _hookId;
private bool _disposed;
public KeyboardHook()
{
_hookId = SetHook(HookCallback);
}
~KeyboardHook()
{
Dispose(false);
}
public delegate bool KeyUpEventHandler(object sender, Win32.KbdllhooksStruct e);
public KeyUpEventHandler KeyUpEvent { get; set; }
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private static nint SetHook(Win32.HookProc lpfn)
{
using var process = Process.GetCurrentProcess();
using var module = process.MainModule;
return Win32.SetWindowsHookExA(Win32.WH_KEYBOARD_LL, lpfn, module!.BaseAddress, 0);
}
private void Dispose(bool disposing)
{
if (_disposed) {
return;
}
if (disposing) {
//
}
if (_hookId != default) {
Win32.UnhookWindowsHookExA(_hookId);
}
_disposed = true;
}
private nint HookCallback(int nCode, nint wParam, nint lParam)
{
// ReSharper disable once InvertIf
if (nCode >= 0 && wParam == Win32.WM_KEYDOWN) {
var hookStruct = (Win32.KbdllhooksStruct)Marshal.PtrToStructure(lParam, typeof(Win32.KbdllhooksStruct))!;
if (KeyUpEvent?.Invoke(null, hookStruct) ?? false) {
return -1;
}
}
return Win32.CallNextHookEx(_hookId, nCode, wParam, lParam);
}
}
#endif