Martin Delille
Martin Delille

Reputation: 11810

Up, Down, Left and Right arrow keys do not trigger KeyDown event

I am building an application where all the key input must be handled by the windows itself.

I set tabstop to false for each control witch could grab the focus except a panel (but I don't know if it has effect).

I set KeyPreview to true and I am handling the KeyDown event on this form.

My problem is that sometimes the arrow key aren't responsive anymore:

Have you an idea why my arrow key suddenly stop firing event?

Upvotes: 90

Views: 191126

Answers (10)

codeDom
codeDom

Reputation: 1779

protected override bool IsInputKey(Keys keyData)
{
    if (((keyData & Keys.Up) == Keys.Up)
        || ((keyData & Keys.Down) == Keys.Down)
        || ((keyData & Keys.Left) == Keys.Left)
        || ((keyData & Keys.Right) == Keys.Right))
        return true;
    else
        return base.IsInputKey(keyData);
}

Upvotes: 1

snarf
snarf

Reputation: 2862

See Rodolfo Neuber's reply for the best answer


(My original answer):

Derive from a control class and you can override the ProcessCmdKey method. Microsoft chose to omit these keys from KeyDown events because they affect multiple controls and move the focus, but this makes it very difficult to make an app react to these keys in any other way.

Upvotes: 18

4mla1fn
4mla1fn

Reputation: 303

i had the same problem and was already using the code in the selected answer. this link was the answer for me; maybe for others also.

How to disable navigation on WinForm with arrows in C#?

Upvotes: 0

Janez Krnc
Janez Krnc

Reputation: 41

I had a similar issue when calling the WPF window out of WinForms.

var wpfwindow = new ScreenBoardWPF.IzbiraProjekti();
    ElementHost.EnableModelessKeyboardInterop(wpfwindow);
    wpfwindow.Show();

However, showing window as a dialog, it worked

var wpfwindow = new ScreenBoardWPF.IzbiraProjekti();
    ElementHost.EnableModelessKeyboardInterop(wpfwindow);
    wpfwindow.ShowDialog();

Hope this helps.

Upvotes: 2

alpha
alpha

Reputation: 690

    protected override bool IsInputKey(Keys keyData)
    {
        switch (keyData)
        {
            case Keys.Right:
            case Keys.Left:
            case Keys.Up:
            case Keys.Down:
                return true;
            case Keys.Shift | Keys.Right:
            case Keys.Shift | Keys.Left:
            case Keys.Shift | Keys.Up:
            case Keys.Shift | Keys.Down:
                return true;
        }
        return base.IsInputKey(keyData);
    }
    protected override void OnKeyDown(KeyEventArgs e)
    {
        base.OnKeyDown(e);
        switch (e.KeyCode)
        {
            case Keys.Left:
            case Keys.Right:
            case Keys.Up:
            case Keys.Down:
                if (e.Shift)
                {

                }
                else
                {
                }
                break;                
        }
    }

Upvotes: 65

Marcus.D
Marcus.D

Reputation: 769

The best way to do, I think, is to handle it like the MSDN said on http://msdn.microsoft.com/en-us/library/system.windows.forms.control.previewkeydown.aspx

But handle it, how you really need it. My way (in the example below) is to catch every KeyDown ;-)

    /// <summary>
    /// onPreviewKeyDown
    /// </summary>
    /// <param name="e"></param>
    protected override void OnPreviewKeyDown(PreviewKeyDownEventArgs e)
    {
        e.IsInputKey = true;
    }

    /// <summary>
    /// onKeyDown
    /// </summary>
    /// <param name="e"></param>
    protected override void OnKeyDown(KeyEventArgs e)
    {
        Input.SetFlag(e.KeyCode);
        e.Handled = true;
    }

    /// <summary>
    /// onKeyUp
    /// </summary>
    /// <param name="e"></param>
    protected override void OnKeyUp(KeyEventArgs e)
    {
        Input.RemoveFlag(e.KeyCode);
        e.Handled = true;
    }

Upvotes: 0

Rodolfo Neuber
Rodolfo Neuber

Reputation: 3481

I was having the exact same problem. I considered the answer @Snarfblam provided; however, if you read the documentation on MSDN, the ProcessCMDKey method is meant to override key events for menu items in an application.

I recently stumbled across this article from microsoft, which looks quite promising: http://msdn.microsoft.com/en-us/library/system.windows.forms.control.previewkeydown.aspx. According to microsoft, the best thing to do is set e.IsInputKey=true; in the PreviewKeyDown event after detecting the arrow keys. Doing so will fire the KeyDown event.

This worked quite well for me and was less hack-ish than overriding the ProcessCMDKey.

Upvotes: 89

vaynenick
vaynenick

Reputation: 11

In order to capture keystrokes in a Forms control, you must derive a new class that is based on the class of the control that you want, and you override the ProcessCmdKey().

protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
    //handle your keys here
}

Example :

protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
    //capture up arrow key
    if (keyData == Keys.Up )
    {
        MessageBox.Show("You pressed Up arrow key");
        return true;
    }

    return base.ProcessCmdKey(ref msg, keyData);
}

Full source...Arrow keys in C#

Vayne

Upvotes: 1

Marcel
Marcel

Reputation: 239

I'm using PreviewKeyDown

    private void _calendar_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e){
        switch (e.KeyCode){
            case Keys.Down:
            case Keys.Right:
                //action
                break;
            case Keys.Up:
            case Keys.Left:
                //action
                break;
        }
    }

Upvotes: 19

Maxim Zaslavsky
Maxim Zaslavsky

Reputation: 18065

Unfortunately, it is quite difficult to accomplish this with the arrow keys, due to restrictions in KeyDown events. However, there are a few ways to get around this:

  • As @Snarfblam stated, you can override the ProcessCmdKey method, which retains the ability to parse arrow key presses.
  • As the accepted answer from this question states, XNA has a built-in method called Keyboard.GetState(), which allows you to use arrow key inputs. However, WinForms doesn't have this, but it can be done through a P/Invoke, or by using a class that helps with it.

I recommend trying to use that class. It's quite simple to do so:

var left = KeyboardInfo.GetKeyState(Keys.Left);
var right = KeyboardInfo.GetKeyState(Keys.Right);
var up = KeyboardInfo.GetKeyState(Keys.Up);
var down = KeyboardInfo.GetKeyState(Keys.Down);

if (left.IsPressed)
{
//do something...
}

//etc...

If you use this in combination with the KeyDown event, I think you can reliably accomplish your goal.

Upvotes: 2

Related Questions