Sebastian
Sebastian
CC#
Created by Sebastian on 1/28/2024 in #help
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);
}
}
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?
11 replies