How to detect the currently pressed key?

Viewed 268805

In Windows Forms, you can know, at any time, the current position of the cursor thanks to the Cursors class.

The same thing doesn't seem to be available for the keyboard. Is it possible to know if, for example, the Shift key is pressed?

Is it absolutely necessary to track down every keyboard notification (KeyDown and KeyUp events)?

12 Answers
if ((Control.ModifierKeys & Keys.Shift) != 0) 

This will also be true if Ctrl+Shift is down. If you want to check whether Shift alone is pressed,

if (Control.ModifierKeys == Keys.Shift)

If you're in a class that inherits Control (such as a form), you can remove the Control.

The code below is how to detect almost all currently pressed keys, not just the Shift key.

private KeyMessageFilter m_filter = new KeyMessageFilter();

private void Form1_Load(object sender, EventArgs e)
{
    Application.AddMessageFilter(m_filter);
}


public class KeyMessageFilter : IMessageFilter
{
    private const int WM_KEYDOWN = 0x0100;
    private const int WM_KEYUP = 0x0101;
    private bool m_keyPressed = false;

    private Dictionary<Keys, bool> m_keyTable = new Dictionary<Keys, bool>();

    public Dictionary<Keys, bool> KeyTable
    {
        get { return m_keyTable; }
        private set { m_keyTable = value; }
    }

    public bool IsKeyPressed()
    {
        return m_keyPressed;
    }

    public bool IsKeyPressed(Keys k)
    {
        bool pressed = false;

        if (KeyTable.TryGetValue(k, out pressed))
        {
            return pressed;
        }

        return false;
    }

    public bool PreFilterMessage(ref Message m)
    {
        if (m.Msg == WM_KEYDOWN)
        {
            KeyTable[(Keys)m.WParam] = true;

            m_keyPressed = true;
        }

        if (m.Msg == WM_KEYUP)
        {
            KeyTable[(Keys)m.WParam] = false;

            m_keyPressed = false;
        }

        return false;
    }
}

You can also look at the following if you use WPF or reference System.Windows.Input

if (Keyboard.Modifiers == ModifierKeys.Shift)

The Keyboard namespace can also be used to check the pressed state of other keys with Keyboard.IsKeyDown(Key), or if you are subscribing to a KeyDownEvent or similar event, the event arguments carry a list of currently pressed keys.

You can P/Invoke down to the Win32 GetAsyncKeyState to test any key on the keyboard.

You can pass in values from the Keys enum (e.g. Keys.Shift) to this function, so it only requires a couple of lines of code to add it.

if (Control.ModifierKeys == Keys.Shift)
    //Shift is pressed

The cursor x/y position is a property, and a keypress (like a mouse click/mousemove) is an event. Best practice is usually to let the interface be event driven. About the only time you would need the above is if you're trying to do a shift + mouseclick thing.

If you need to listen to keys in any generic class what are pressed when a 'Form' Window, this is your code. It doesnt listen to global windows key events, so it cannot be used to see keys when the window is not active.

Form.cs

public partial class Form1 : Form
{
    public Form1()
    {
        // Some other Code
        // Register all Keys pressed
        this.KeyPreview = true;
        KeyHandler.Instance.Init();
        this.KeyDown += Form1_KeyDown;
        this.KeyUp += Form1_KeyUp;
        // Some other Code in the constructor
    }

    private void Form1_KeyUp(object sender, KeyEventArgs e)
    {
        // Fire event when a key is released
        KeyHandler.Instance.FireKeyUp(sender, e);
    }

    private void Form1_KeyDown(object sender, KeyEventArgs e)
    {
        // Fire event when a key is pressed
        KeyHandler.Instance.FireKeyDown(sender, e);
    }
}

KeyHandler.cs KeyHandler is a Singleton Class and can be accessed in any other Object through Handler.Instance... Easy right.

public class KeyHandler
{
    #region Singleton
    private static KeyHandler instance;
    private KeyHandler()
    {
        currentlyPressedKeys = new List<Keys>();
    }

    public static KeyHandler Instance
    {
        get
        {
            if (instance is null)
            {
                instance = new KeyHandler();
            }
            return instance;
        }
    }
    #endregion Singleton

    private List<Keys> currentlyPressedKeys;
    public List<Keys> GetCurrentlyPressedKeys { get { return currentlyPressedKeys; } }

    public void FireKeyDown(object sender, KeyEventArgs e)
    {
        if (!currentlyPressedKeys.Contains(e.KeyCode))
        {
            currentlyPressedKeys.Add(e.KeyCode);
            KeyEventKeyPressed(sender, e);
        }
    }

    public void FireKeyUp(object sender, KeyEventArgs e)
    {
        currentlyPressedKeys.Remove(e.KeyCode);
        KeyEventKeyReleased(sender, e);
    }

    public event EventHandler<KeyEventArgs> KeyPressed;
    protected virtual void KeyEventKeyPressed(object sender, KeyEventArgs e)
    {
        EventHandler<KeyEventArgs> handler = KeyPressed;
        handler?.Invoke(sender, e);
    }

    public event EventHandler<KeyEventArgs> KeyReleased;
    protected virtual void KeyEventKeyReleased(object sender, KeyEventArgs e)
    {
        EventHandler<KeyEventArgs> handler = KeyReleased;
        handler?.Invoke(sender, e);
    }

    public void Init()
    {
        // Nothing to initialize yet
    }
}

// In any other Class/Object its now possible to receive KeyEvents that are fired when the 'Form' is active. So its possible to listen to key events in any Control object or anything else. Its possible to see if e.g. multiple keys are pressed like Shift+Ctrl+Q or something like that.

public class SomeClass
{
    public SomeClass()
    {
        KeyHandler.instance.KeyPressed += Instance_KeyPressed
        KeyHandler.Instance.KeyReleased += Instance_KeyReleased;
    }

    public void SomeMethod()
    {
        if (KeyHandler.Instance.GetCurrentlyPressedKeys.Contains(Keys.ShiftKey))
        {
            // Do Stuff when the method has a key (e.g. Shift/Control...) pressed
        }
    }

    private void Instance_KeyPressed(object sender, KeyEventArgs e)
    {
        // Any Key was pressed, do Stuff then
    }

    private void Instance_KeyReleased(object sender, KeyEventArgs e)
    {
        // Do Stuff when a Key was Released
    }
}
Related