Files
better-genshin-impact/Fischless.KeyboardCapture/KeyboardHook.cs
ema 5c557ae684 fix: hot key like binding name error
merge from Fischless.KeyboardCapture
2023-12-18 23:53:16 +08:00

99 lines
3.0 KiB
C#

using System.Diagnostics;
using System.Runtime.InteropServices;
using Vanara.PInvoke;
namespace Fischless.KeyboardCapture;
public sealed class KeyboardHook : IDisposable
{
public event KeyboardEventHandler KeyDown = null!;
public event KeyboardPressEventHandler KeyPress = null!;
public event KeyboardEventHandler KeyUp = null!;
private User32.SafeHHOOK hook = new(IntPtr.Zero);
private User32.HookProc? hookProc;
~KeyboardHook()
{
Dispose();
}
public void Dispose()
{
Stop();
}
public void Start()
{
if (hook.IsNull)
{
hookProc = KeyboardHookProc;
hook = User32.SetWindowsHookEx(User32.HookType.WH_KEYBOARD_LL, hookProc, Kernel32.GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName), 0);
User32.SetWindowsHookEx(User32.HookType.WH_KEYBOARD_LL, hookProc, IntPtr.Zero, (int)Kernel32.GetCurrentThreadId());
if (hook.IsNull)
{
Stop();
throw new SystemException("Failed to install keyboard hook");
}
}
}
public void Stop()
{
bool retKeyboard = true;
if (!hook.IsNull)
{
retKeyboard = User32.UnhookWindowsHookEx(hook);
hook = new(IntPtr.Zero);
}
if (!retKeyboard)
{
throw new SystemException("Failed to uninstall hook");
}
}
private nint KeyboardHookProc(int nCode, nint wParam, nint lParam)
{
if (nCode >= 0)
{
if (KeyDown != null || KeyUp != null || KeyPress != null)
{
User32.KBDLLHOOKSTRUCT hookStruct = (User32.KBDLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(User32.KBDLLHOOKSTRUCT))!;
if (KeyDown != null && (wParam == (nint)User32.WindowMessage.WM_KEYDOWN || wParam == (nint)User32.WindowMessage.WM_SYSKEYDOWN))
{
KeyboardKeys keyData = (KeyboardKeys)hookStruct.vkCode;
KeyboardEventArgs e = new(keyData);
KeyDown(this, e);
}
if (KeyPress != null && wParam == (nint)User32.WindowMessage.WM_KEYDOWN)
{
byte[] keyState = new byte[256];
_ = User32.GetKeyboardState(keyState);
if (User32.ToAscii(hookStruct.vkCode, hookStruct.scanCode, keyState, out ushort lpChar, hookStruct.flags) == 1)
{
KeyboardPressEventArgs e = new((char)lpChar);
KeyPress(this, e);
}
}
if (KeyUp != null && (wParam == (nint)User32.WindowMessage.WM_KEYUP || wParam == (nint)User32.WindowMessage.WM_SYSKEYUP))
{
KeyboardKeys keyData = (KeyboardKeys)hookStruct.vkCode;
KeyboardEventArgs e = new(keyData);
KeyUp(this, e);
}
}
}
return User32.CallNextHookEx(hook, nCode, wParam, lParam);
}
}