Я сшил вместе код, который я нашел в интернете, WH_KEYBOARD_LL класс помощника:
Поместите следующий код в некоторые из ваших utils libs, пусть это будет YourUtils.cs:
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
using System.Windows.Input;
namespace MYCOMPANYHERE.WPF.KeyboardHelper
{
    public class KeyboardListener : IDisposable
    {
        private static IntPtr hookId = IntPtr.Zero;
        [MethodImpl(MethodImplOptions.NoInlining)]
        private IntPtr HookCallback(
            int nCode, IntPtr wParam, IntPtr lParam)
        {
            try
            {
                return HookCallbackInner(nCode, wParam, lParam);
            }
            catch
            {
                Console.WriteLine("There was some error somewhere...");
            }
            return InterceptKeys.CallNextHookEx(hookId, nCode, wParam, lParam);
        }
        private IntPtr HookCallbackInner(int nCode, IntPtr wParam, IntPtr lParam)
        {
            if (nCode >= 0)
            {
                if (wParam == (IntPtr)InterceptKeys.WM_KEYDOWN)
                {
                    int vkCode = Marshal.ReadInt32(lParam);
                    if (KeyDown != null)
                        KeyDown(this, new RawKeyEventArgs(vkCode, false));
                }
                else if (wParam == (IntPtr)InterceptKeys.WM_KEYUP)
                {
                    int vkCode = Marshal.ReadInt32(lParam);
                    if (KeyUp != null)
                        KeyUp(this, new RawKeyEventArgs(vkCode, false));
                }
            }
            return InterceptKeys.CallNextHookEx(hookId, nCode, wParam, lParam);
        }
        public event RawKeyEventHandler KeyDown;
        public event RawKeyEventHandler KeyUp;
        public KeyboardListener()
        {
            hookId = InterceptKeys.SetHook((InterceptKeys.LowLevelKeyboardProc)HookCallback);
        }
        ~KeyboardListener()
        {
            Dispose();
        }
        #region IDisposable Members
        public void Dispose()
        {
            InterceptKeys.UnhookWindowsHookEx(hookId);
        }
        #endregion
    }
    internal static class InterceptKeys
    {
        public delegate IntPtr LowLevelKeyboardProc(
            int nCode, IntPtr wParam, IntPtr lParam);
        public static int WH_KEYBOARD_LL = 13;
        public static int WM_KEYDOWN = 0x0100;
        public static int WM_KEYUP = 0x0101;
        public static IntPtr SetHook(LowLevelKeyboardProc proc)
        {
            using (Process curProcess = Process.GetCurrentProcess())
            using (ProcessModule curModule = curProcess.MainModule)
            {
                return SetWindowsHookEx(WH_KEYBOARD_LL, proc,
                    GetModuleHandle(curModule.ModuleName), 0);
            }
        }
        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern IntPtr SetWindowsHookEx(int idHook,
            LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);
        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool UnhookWindowsHookEx(IntPtr hhk);
        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode,
            IntPtr wParam, IntPtr lParam);
        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern IntPtr GetModuleHandle(string lpModuleName);
    }
    public class RawKeyEventArgs : EventArgs
    {
        public int VKCode;
        public Key Key;
        public bool IsSysKey;
        public RawKeyEventArgs(int VKCode, bool isSysKey)
        {
            this.VKCode = VKCode;
            this.IsSysKey = isSysKey;
            this.Key = System.Windows.Input.KeyInterop.KeyFromVirtualKey(VKCode);
        }
    }
    public delegate void RawKeyEventHandler(object sender, RawKeyEventArgs args);
}
 Что я использую так:
App.xaml:
<Application ...
    Startup="Application_Startup"
    Exit="Application_Exit">
    ...
 App.xaml.cs:
public partial class App : Application
{
    KeyboardListener KListener = new KeyboardListener();
    private void Application_Startup(object sender, StartupEventArgs e)
    {
        KListener.KeyDown += new RawKeyEventHandler(KListener_KeyDown);
    }
    void KListener_KeyDown(object sender, RawKeyEventArgs args)
    {
        Console.WriteLine(args.Key.ToString());
        // I tried writing the data in file here also, to make sure the problem is not in Console.WriteLine
    }
    private void Application_Exit(object sender, ExitEventArgs e)
    {
        KListener.Dispose();
    }
}
 Проблема в том, что он перестает работать после нажатия клавиш. Никакой ошибки не возникает, что так всегда, я просто ничего не получаю от вывода через некоторое время. Когда он перестает работать, я не могу найти сплошной рисунок.
Воспроизведение этой проблемы довольно простое, поразило некоторые клавиши, как безумный человек, обычно за окном.
Я подозреваю, что есть какая-то проблема с резьбой, кто-нибудь понял, как это сделать?
Я уже пробовал:
-  Замена 
return HookCallbackInner(nCode, wParam, lParam);с чем-то простым. - Замените его асинхронным вызовом, пытаясь установить Sleep 5000ms (и т.д.).
 
Асинхронный вызов не помог ему работать лучше, он всегда останавливается, когда пользователь некоторое время удерживает одну букву.