Windows keyboard hook (SetWindowsHookExA) doesn't get called.

Simplified version:
KeyboardListener.KeyPress += (key) =>
{
    Console.WriteLine(Enum.GetName(key));
};
KeyboardListener.Listen();

await Task.Delay(-1);

public static unsafe partial class KeyboardListener
{
    private const string User32 = "user32";
    private const string Kernel32 = "kernel32";
    private const int KeyboardId = 13;
    private const int KeyDown = 0x0100;

    [LibraryImport(User32, SetLastError = true)]
    private static partial nuint SetWindowsHookExA(int idHook, delegate* unmanaged<int, nuint, nint, nint> lpfn, nuint hmod, uint dwThreadId);

    [LibraryImport(User32, SetLastError = true)]
    private static partial nint CallNextHookEx(nuint hhk, int nCode, nuint wParam, nint lParam);

    [LibraryImport(User32, SetLastError = true)]
    private static partial int UnhookWindowsHookEx(nuint hhk);

    private static nuint _handle = 0;

    public static event Action<ConsoleKey>? KeyPress;

    public static void Listen()
    {
        nuint hmod = (nuint)Marshal.GetHINSTANCE(typeof(KeyboardListener).Module);
        _handle = SetWindowsHookExA(KeyboardId, &Hook, hmod, 0);
    }

    public static void Stop()
    {
        UnhookWindowsHookEx(_handle);
    }

    [UnmanagedCallersOnly]
    private static nint Hook(int nCode, nuint wParam, nint lParam)
    {
        if (nCode >= 0 && wParam == KeyDown)
        {
            ConsoleKey key = (ConsoleKey)lParam;
            KeyPress?.Invoke(key);
        }

        return CallNextHookEx(0, nCode, wParam, lParam);
    }
}

It's doing "something" - when the application is running, key presses have some delay. What it's not doing however, is actually calling the Hook method. Any pointers?
Was this page helpful?