10

I have developed an On Screen Keyboard in WPF. I need to capture the key press event (via Key Board) in order to keep a track of Caps Lock, Shift etc (whether they are pressed). Please note that my application loses focus when any other application (say notepad) is opened.

Could anyone suggest how to achieve this in WPF? in short, my WPF application needs to capture the key press events even though it does not have focus.

CharithJ
  • 46,289
  • 20
  • 116
  • 131
Kishor
  • 101
  • 1
  • 1
  • 4
  • 3
    You have to use the Windows API to register a keyboard hook with Windows. https://blogs.msdn.microsoft.com/toub/2006/05/03/low-level-keyboard-hook-in-c/ – Logan Fields Jun 02 '17 at 23:18

3 Answers3

1

If you want your WPF application to be able to detect and handle key presses even when it is not currently activated or focused on the screen you could implement what is known as global hot keys in Windows.

The following two methods can be added to a C# class to be able to register and unregister a global hot key:

[DllImport("user32.dll")]
private static extern bool RegisterHotKey(IntPtr hWnd, int id, uint fsModifiers, uint vk);
 
[DllImport("user32.dll")]
private static extern bool UnregisterHotKey(IntPtr hWnd, int id);

Sample code

using System;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Interop;
 
namespace Mm.Wpf.GlobalHotKeys
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        [DllImport("user32.dll")]
        private static extern bool RegisterHotKey(IntPtr hWnd, int id, uint fsModifiers, uint vk);
 
        [DllImport("user32.dll")]
        private static extern bool UnregisterHotKey(IntPtr hWnd, int id);
 
        private const int HOTKEY_ID = 9000;
 
        //Modifiers:
        private const uint MOD_NONE = 0x0000; //(none)
        private const uint MOD_ALT = 0x0001; //ALT
        private const uint MOD_CONTROL = 0x0002; //CTRL
        private const uint MOD_SHIFT = 0x0004; //SHIFT
        private const uint MOD_WIN = 0x0008; //WINDOWS
        //CAPS LOCK:
        private const uint VK_CAPITAL = 0x14;
 
        public MainWindow()
        {
            InitializeComponent();
        }
 
        private IntPtr _windowHandle;
        private HwndSource _source;
        protected override void OnSourceInitialized(EventArgs e)
        {
            base.OnSourceInitialized(e);
 
            _windowHandle = new WindowInteropHelper(this).Handle;
            _source = HwndSource.FromHwnd(_windowHandle);
            _source.AddHook(HwndHook);
 
            RegisterHotKey(_windowHandle, HOTKEY_ID, MOD_CONTROL, VK_CAPITAL); //CTRL + CAPS_LOCK
        }
 
        private IntPtr HwndHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
        {
            const int WM_HOTKEY = 0x0312;
            switch (msg)
            {
                case WM_HOTKEY:
                    switch (wParam.ToInt32())
                    {
                        case HOTKEY_ID:
                            int vkey = (((int)lParam >> 16) & 0xFFFF);
                            if (vkey == VK_CAPITAL)
                            {
                                tblock.Text += "CapsLock was pressed" + Environment.NewLine;
                            }
                            handled = true;
                            break;
                    }
                    break;
            }
            return IntPtr.Zero;
        }
 
        protected override void OnClosed(EventArgs e)
        {
            _source.RemoveHook(HwndHook);
            UnregisterHotKey(_windowHandle, HOTKEY_ID);
            base.OnClosed(e);
        }
    }
}
<Window x:Class="Mm.Wpf.GlobalHotKeys.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <TextBlock x:Name="tblock"></TextBlock>
    </Grid>
</Window>

Reference

CharithJ
  • 46,289
  • 20
  • 116
  • 131
0

This was helpful for me : Disable WPF Window Focus

Its not exactly the same as your problem, he is trying to catch an event without getting focus , but its a good starting point

-2

I use a simple code behind:

In the xaml I use a KeyDown event called MyTestKey.

<Window x:Class="MyApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        KeyDown="myTestKey" >

This is what the keydown routine looks like where I check for the number 1:

private void myTestKey(object sender, KeyEventArgs e)
{
            if ((e.Key == Key.D1) || (e.Key == Key.NumPad1))
            {
                //do some stuff here
                return;
            }
}

This is an easy way to get to any key. I hope this helps.

Mark W
  • 811
  • 2
  • 11
  • 17