138

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)?

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

12 Answers12

174
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.

vahid abdi
  • 9,636
  • 4
  • 29
  • 35
SLaks
  • 868,454
  • 176
  • 1,908
  • 1,964
  • 8
    Unless I'm missing something, you haven't answered the question properly. The OP is asking about all keys and used the Shift key as an example only. So how do you detect other keys such as A to Z, 0 to 9 etc. – Ash Dec 18 '09 at 10:03
  • 2
    Given that he accepted the answer, it appears that he only needed modifier keys. If you want other keys, you'll need to call the `GetKeyState` API function. – SLaks Dec 18 '09 at 13:17
  • 2
    no need for GetKeyState. You just need to add a message filter. See my answer. – Ash Jan 23 '10 at 16:33
  • 3
    For a **WPF solution** you can use `Keyboard.Modifiers == ModifierKeys.Shift` (for those that came here on a search) – Bill Tarbell Jul 07 '16 at 17:34
  • 3
    instead of `(Control.ModifierKeys & Keys.Shift) != 0` one can use `Control.ModifierKeys.HasFlag(Keys.Shift)` – tomuxmon Jun 21 '17 at 07:02
  • @tomuxmon: This answer was written before `HasFlag` existed :) – SLaks Jun 21 '17 at 14:04
58

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;
    }
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Ash
  • 60,973
  • 31
  • 151
  • 169
  • 1
    `GetKeyState` would be more efficient. There's no point in tracking all of the keys when Windows does it for you already. – SLaks Jan 23 '10 at 23:51
  • 3
    @Slaks, unless you have some benchmark data, you're guessing. Moreover GetKeyState will tell you the state of a key, *if* you can trap that keyboard event in the first place. My reading of the question is that the OP wants to know how to get the state of a key at *any time*. So GetKeyState by itself is useless. – Ash Jan 24 '10 at 03:08
  • 3
    How exactly would you utilize this to show the keys being pressed? – Gabriel Ryan Nahmias Nov 11 '13 at 10:55
  • Gabriel: Create an instance of KeyMessageFilter as a field in your form. Pass it to Application.AddMessageFilter() in Form_Load. Then call IsKeyPressed() on this instance for each/any key that you are interested in. – Ash Mar 03 '17 at 13:26
  • @Ash thanks for your answer - would you be able to do a code example for checking for the SHIFT key etc. above? – BenKoshy Mar 26 '18 at 21:28
  • This is a nice example class, but for my purpose this did not work. When the key is pressed during a button click, the release event will not arrive. So next time I press my button, KeyMessageFilter reports that the key is still pressed, IsKeyPressed remains true. I changed to using the Control key and the solution that was approved here, using ModifierKeys. – Goodies Feb 22 '21 at 11:07
25

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.

Athanviel
  • 199
  • 1
  • 3
  • 15
Jeff Wain
  • 1,010
  • 8
  • 12
  • 2
    Actually Keyboard.Modifiers do not always work properly. Had to find the hard way: http://discoveringdotnet.alexeyev.org/2008/09/keyboardmodifiers-sometimes-doesnt-work.html – Maxim Alexeyev Jul 08 '09 at 20:39
  • Except this is not using Forms modifiers, System.Windows.Input modifiers is a different namespace and has worked fine for us every time. – Jeff Wain Jul 08 '09 at 21:04
24

Most of these answers are either far too complicated or don't seem to work for me (e.g. System.Windows.Input doesn't seem to exist). Then I found some sample code which works fine: http://www.switchonthecode.com/tutorials/winforms-accessing-mouse-and-keyboard-state

In case the page disappears in the future I am posting the relevant source code below:

using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace MouseKeyboardStateTest
{
  public abstract class Keyboard
  {
    [Flags]
    private enum KeyStates
    {
      None = 0,
      Down = 1,
      Toggled = 2
    }

    [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
    private static extern short GetKeyState(int keyCode);

    private static KeyStates GetKeyState(Keys key)
    {
      KeyStates state = KeyStates.None;

      short retVal = GetKeyState((int)key);

      //If the high-order bit is 1, the key is down
      //otherwise, it is up.
      if ((retVal & 0x8000) == 0x8000)
        state |= KeyStates.Down;

      //If the low-order bit is 1, the key is toggled.
      if ((retVal & 1) == 1)
        state |= KeyStates.Toggled;

      return state;
    }

    public static bool IsKeyDown(Keys key)
    { 
      return KeyStates.Down == (GetKeyState(key) & KeyStates.Down);
    }

    public static bool IsKeyToggled(Keys key)
    { 
      return KeyStates.Toggled == (GetKeyState(key) & KeyStates.Toggled);
    }
  }
}
parsley72
  • 8,449
  • 8
  • 65
  • 98
15

Since .NET Framework version 3.0, it is possible to use the Keyboard.IsKeyDown method from the new System.Windows.Input namespace. For instance:

if (((Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)) && Keyboard.IsKeyDown(Key.F))
{
    // CTRL + F is currently pressed
}

Even though it's part of WPF, that method works fine for WinForm applications (provided that you add references to PresentationCore.dll and WindowsBase.dll). Unfortunately, however, the 3.0 and 3.5 versions of the Keyboard.IsKeyDown method did not work for WinForm applications. Therefore, if you do want to use it in a WinForm application, you'll need to be targeting .NET Framework 4.0 or later in order for it to work.

Steven Doggart
  • 43,358
  • 8
  • 68
  • 105
  • just a note, this is for WPF only – Diego Vieira Apr 04 '13 at 15:45
  • 2
    @DiegoVieira Actually, that's not true. The functionality was added as part of WPF, and it requires that those WPF libraries be referenced, but the `Keyboard.IsKeyDown` method works, even in a WinForm project. – Steven Doggart Apr 04 '13 at 16:03
  • Indeed, you have to add PresentationCore.dll – Diego Vieira Apr 04 '13 at 16:22
  • 3
    Note this doesn't work (in WinForms) if targeting .Net 3.5 or earlier, only 4.0+, due to change in implementation of Win32KeyboardDevice.GetKeyStatesFromSystem(Key) :( – LMK Oct 07 '14 at 23:05
  • @LMK Nice catch. I tested it myself and verified what you said. I updated my answer to reflect that information. Thanks! – Steven Doggart Oct 08 '14 at 13:20
8

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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Jason Williams
  • 56,972
  • 11
  • 108
  • 137
5
if ((ModifierKeys == Keys.Control) && ((e.KeyChar & (char)Keys.F) != 0))
{
     // CTRL+F pressed !
}
Mahdi
  • 57
  • 1
  • 2
3
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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Rob Elliott
  • 1,998
  • 19
  • 25
3

The best way I have found to manage keyboard input on a Windows Forms form is to process it after the keystroke and before the focused control receives the event. Microsoft maintains a built-in Form-level property named .KeyPreview to facilitate this precise thing:

public frmForm()
{
    // ...
    frmForm.KeyPreview = true;
    // ...
}

Then the form's _KeyDown, _KeyPress, and / or _KeyUp events can be marshaled to access input events before the focused form control ever sees them, and you can apply handler logic to capture the event there or allow it to pass through to the focused form control.

Although not as structurally graceful as XAML's event-routing architecture, it makes management of form-level functions in Winforms far simpler. See the MSDN notes on KeyPreview for caveats.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Hardryv
  • 755
  • 7
  • 12
2
if (Form.ModifierKeys == Keys.Shift)

does work for a text box if the above code is in the form's keydown event and no other control captures the keydown event for the key down.

Also one may wish stop further key processing with:

e.Handled = true;
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
g.g
  • 21
  • 1
0

In WinForms:

if( Form.ModifierKeys == Keys.Shift )

It sounds like a duplicate of Stack Overflow question Detect Shift key is pressed without using events in Windows Forms?.

Community
  • 1
  • 1
Will Eddins
  • 13,628
  • 5
  • 51
  • 85
0

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
    }
}
Ramil Aliyev 007
  • 4,437
  • 2
  • 31
  • 47
Zeradun
  • 1
  • 2