1

How do I capture a key down event in WPF even if my application is not focused?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131

3 Answers3

3

For me, the best way is this:

public MainWindow()
{
    InitializeComponent();

    CompositionTarget.Rendering += new EventHandler(CompositionTarget_Rendering);
}

void CompositionTarget_Rendering(object sender, EventArgs e)
{
    if ((Keyboard.GetKeyStates(Key.W) & KeyStates.Down) > 0)
    {
        player1.walk();
    }
} 

The rendering event runs every time.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
alansiqueira27
  • 8,129
  • 15
  • 67
  • 111
3

Global keyboard hook can slow down your debugging.

I prefer to use this approach:

  1. Create KeyboardListener class

    public class KeyboardListener : IDisposable
    {
        private readonly Thread keyboardThread;
    
        //Here you can put those keys that you want to capture
        private readonly List<KeyState> numericKeys = new List<KeyState>
        {
            new KeyState(Key.D0),
            new KeyState(Key.D1),
            new KeyState(Key.D2),
            new KeyState(Key.D3),
            new KeyState(Key.D4),
            new KeyState(Key.D5),
            new KeyState(Key.D6),
            new KeyState(Key.D7),
            new KeyState(Key.D8),
            new KeyState(Key.D9),
            new KeyState(Key.NumPad0),
            new KeyState(Key.NumPad1),
            new KeyState(Key.NumPad2),
            new KeyState(Key.NumPad3),
            new KeyState(Key.NumPad4),
            new KeyState(Key.NumPad5),
            new KeyState(Key.NumPad6),
            new KeyState(Key.NumPad7),
            new KeyState(Key.NumPad8),
            new KeyState(Key.NumPad9),
            new KeyState(Key.Enter)
        };
    
        private bool isRunning = true;
    
        public KeyboardListener()
        {
            keyboardThread = new Thread(StartKeyboardListener) { IsBackground = true };
            keyboardThread.Start();
        }
    
        private void StartKeyboardListener()
        {
            while (isRunning)
            {
                Thread.Sleep(15);
                if (Application.Current != null)
                {
                    Application.Current.Dispatcher.Invoke(() =>
                    {
                        if (Application.Current.Windows.Count > 0)
                        {
                            foreach (var keyState in numericKeys)
                            {
                                if (Keyboard.IsKeyDown(keyState.Key) && !keyState.IsPressed) //
                                {
                                    keyState.IsPressed = true;
                                    KeyboardDownEvent?.Invoke(null, new KeyEventArgs(Keyboard.PrimaryDevice, PresentationSource.FromDependencyObject(Application.Current.Windows[0]), 0, keyState.Key));
                                }
    
                                if (Keyboard.IsKeyUp(keyState.Key))
                                {
                                    keyState.IsPressed = false;
                                }
                            }
                        }
                    });
                }
            }
        }
    
        public event KeyEventHandler KeyboardDownEvent;
    
        /// <summary>
        /// Состояние клавиши
        /// </summary>
        private class KeyState
        {
            public KeyState(Key key)
            {
                this.Key = key;
            }
    
            public Key Key { get; }
            public bool IsPressed { get; set; }
        }
    
        public void Dispose()
        {
            isRunning = false;
            Task.Run(() =>
            {
                if (keyboardThread != null && !keyboardThread.Join(1000))
                {
                    keyboardThread.Abort();
                }
            });
        }
    }
    
  2. Subscribe to KeyboardDownEvent in code-behind (or where you need it).

    public partial class MainWindow : Window
    {
        private KeyboardListener listener;
    
        public MainWindow()
        {
            InitializeComponent();
        }
    
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            listener = new KeyboardListener();
            listener.KeyboardDownEvent += ListenerOnKeyPressed;
        }
    
        private void ListenerOnKeyPressed(object sender, KeyEventArgs e)
        {
            // TYPE YOUR CODE HERE
        }
    
        private void Window_OnUnloaded(object sender, RoutedEventArgs e)
        {
            listener.KeyboardDownEvent -= ListenerOnKeyPressed;
        }
    }
    
  3. Done

Matt McManis
  • 4,475
  • 5
  • 38
  • 93
0

See this questions for hooking the keyboard Using global keyboard hook (WH_KEYBOARD_LL) in WPF / C#

Community
  • 1
  • 1
Homde
  • 4,246
  • 4
  • 34
  • 50