Если нужны горячие клавиши, то используйте RegisterHotKey / UnregisterHotKey
Если надо отлавливать события KeyDown KeyPress KeyUp, то используйте SetWindowsHookEx с параметром WH_KEYBOARD_LL / UnhookWindowsHookEx
private bool hooked = false;
private IntPtr hHook;
private HookProc managedDelegate = InternalCallback;
public event KeyEventHandler KeyDown;
public event KeyEventHandler KeyUp;
public event KeyPressEventHandler KeyPress;
public void StartHook()
{
IntPtr delegt = Marshal.GetFunctionPointerForDelegate(managedDelegate);
hHook = SetWindowsHookEx(HookType.WH_KEYBOARD_LL, delegt, getMainModuleHandle(), 0);
if (hHook == IntPtr.Zero) throw new Win32Exception(Marshal.GetLastWin32Error());
}
public virtual void Unhook()
{
if (!UnhookWindowsHookEx(hHook)) throw new Win32Exception(Marshal.GetLastWin32Error());
}
protected int InternalCallback(int code, IntPtr wParam, IntPtr lParam)
{
if (code >= 0)
{
bool handled = false;
KeyboardHookStruct keyboardHookStruct = (KeyboardHookStruct)Marshal.PtrToStructure(lParam, typeof(KeyboardHookStruct));
if (KeyDown != null && ((int)wParam == WM_KEYDOWN || (int)wParam == WM_SYSKEYDOWN))
{
Keys keyData = (Keys)keyboardHookStruct.VirtualKeyCode;
KeyEventArgs e = new KeyEventArgs(keyData);
KeyDown.Invoke(null, e);
handled = e.Handled;
}
if (KeyPress != null && (int)wParam == WM_KEYDOWN)
{
//Перекодирование сканкодов в Ascii
}
if (KeyUp != null && ((int)wParam == WM_KEYUP || (int)wParam == WM_SYSKEYUP))
{
Keys keyData = (Keys)keyboardHookStruct.VirtualKeyCode;
KeyEventArgs e = new KeyEventArgs(keyData);
KeyUp.Invoke(null, e);
handled = handled || e.Handled;
}
if (handled) return 1;
}
return CallNextHookEx(hHook, code, wParam, lParam);
}
private IntPtr getMainModuleHandle()
{
IntPtr hMod;
using (Process process = Process.GetCurrentProcess())
using (ProcessModule module = process.MainModule)
{
hMod = GetModuleHandle(module.ModuleName);
}
return hMod;
}
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(HookType hook, IntPtr callback,
IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll", SetLastError = true)]
internal static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll")]
internal static extern int CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam,
IntPtr lParam);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string lpModuleName);
private delegate int HookProc(int code, IntPtr wParam, IntPtr lParam);
private const int
WM_KEYDOWN = 0x100,
WM_KEYUP = 0x101,
WM_SYSKEYDOWN = 0x104,
WM_SYSKEYUP = 0x105;
[StructLayout(LayoutKind.Sequential)]
private struct KeyboardHookStruct
{
/// <summary>
/// Specifies a virtual-key code. The code must be a value in the range 1 to 254.
/// </summary>
public int VirtualKeyCode;
/// <summary>
/// Specifies a hardware scan code for the key.
/// </summary>
public int ScanCode;
/// <summary>
/// Specifies the extended-key flag, event-injected flag, context code, and transition-state flag.
/// </summary>
public int Flags;
/// <summary>
/// Specifies the Time stamp for this message.
/// </summary>
public int Time;
/// <summary>
/// Specifies extra information associated with the message.
/// </summary>
public int ExtraInfo;
}
internal enum HookType : int
{
///
WH_JOURNALRECORD = 0,
///
WH_JOURNALPLAYBACK = 1,
///
WH_KEYBOARD = 2,
///
WH_GETMESSAGE = 3,
///
WH_CALLWNDPROC = 4,
///
WH_CBT = 5,
///
WH_SYSMSGFILTER = 6,
///
WH_MOUSE = 7,
///
WH_HARDWARE = 8,
///
WH_DEBUG = 9,
///
WH_SHELL = 10,
///
WH_FOREGROUNDIDLE = 11,
///
WH_CALLWNDPROCRET = 12,
///
WH_KEYBOARD_LL = 13,
///
WH_MOUSE_LL = 14
}