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

10

90

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:

  • The keydown event is not fired when I pressed only an arrow key.

  • The keydown event is fired if I press an arrow key with the control modifier.

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

Seraphina answered 29/10, 2009 at 22:36 Comment(5)
Can you post the code that you've got in your KeyDown event handler.Materse
Maybe this will help you? #903267Backbone
@ Maxim, I'm pretty sure if a window contains any child controls, the key events for arrow keys will be suppressed. The question you linked to dealt with a form with no controls. Daniel Waltrip's problem wasn't really the same.Annihilator
@Snarfblam I'm not sure I understand - why would that be an issue here?Backbone
support.microsoft.com/kb/320584Dilatory
O
65
    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;                
        }
    }
Overdose answered 9/4, 2011 at 17:40 Comment(2)
Note that all the tab stop for controls, should be false.(I faced with such a problem :D)Wellborn
This is actually an hack. Check Rodolfo Neuber answer for correct answer.Holcman
A
89

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.

Artwork answered 19/10, 2011 at 0:6 Comment(4)
This should be the chosen answer, it is way cleaner and it works wonderfully.Beals
Yeah it works! The answer is quite clear, but I want to specify that the IsInputKey is in e class: e.IsInputKey=true.Centenarian
(what does it happens if you do it for all keys without detecting the arrows?)Centenarian
@Centenarian You will lose the Alt for the menusBludge
O
65
    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;                
        }
    }
Overdose answered 9/4, 2011 at 17:40 Comment(2)
Note that all the tab stop for controls, should be false.(I faced with such a problem :D)Wellborn
This is actually an hack. Check Rodolfo Neuber answer for correct answer.Holcman
J
19

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;
        }
    }
Jemadar answered 24/1, 2013 at 11:32 Comment(2)
Worked beautifully for me, no need to inherit/overrideGabar
THIS should be the accepted answer!!! Just use the PreviewKeyDown event. Works with no hacking required. Couldn't be cleaner or simpler.Burberry
A
18

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.

Annihilator answered 29/10, 2009 at 22:51 Comment(3)
It seems that ProcessCmdKey is the only way to handle the keyboard accurately. Thanks!Seraphina
This answer is dead wrong. If I hadn't already overridden OnKeyDown from some base control that already handled the arrow keys (to change the behavior) I would not have known this and implemented it the hard way. See alpha's answer below.Liaoyang
Even alpha's answer doesn't work for my situation,but Snarfblam's does.Thank you!Rickets
B
2

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.

Backbone answered 29/10, 2009 at 23:1 Comment(0)
L
2

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.

Ludeman answered 10/10, 2016 at 21:17 Comment(0)
H
1

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

Hydrodynamic answered 19/6, 2014 at 8:0 Comment(0)
B
1
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);
}
Bludge answered 18/6, 2019 at 20:31 Comment(0)
T
0

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;
    }
Tade answered 20/12, 2014 at 14:11 Comment(0)
P
0

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

Prissie answered 3/1, 2017 at 12:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.