Arrow keys can not be captured in KeyDown event

2011-06-10


In Windows Forms, If you write a KeyDown event method for some keys, such as arrow keys, you might find it doesn't work, but for other keys like A,B,C,D... it work.

The reason is that some Windows Form controls ignore the key press from the TAB key, RETURN key, ESC key, and arrow keys by default, these keys are not considered input keys.

For example,when you press arrow keys on a button, it will causes the focus to move to previous or next control, now the arrow keys are navigation keys, so you can not capture them in KeyDown event.

This rule is not for button control, it also for some other controls, includes User controls.

The solution is using PreviewKeyDown event, not KeyDown event; Or still use KeyDown event, but should set the IsInputKey property to true in PreviewKeyDown; and you have to know the focus will no longer move to the previous or next control.

For example, we have a user control in our project. Before we used code like following:

private void vectShapes_KeyDown(object sender, KeyEventArgs e)
{
    bool eleChanged = false;

    int x, y;

    x = y = 0;

    switch (e.KeyCode)
    {
        case Keys.Left:
        case Keys.A:
            x = -1;
            doMoveEle(x, y);
            eleChanged = true;
            break;
        case Keys.Right:
        case Keys.D:
            x = 1;
            doMoveEle(x, y);
            eleChanged = true;
            break;

        case Keys.Up:
        case Keys.W:
            y = -1;
            doMoveEle(x, y);
            eleChanged = true;
            break;

        case Keys.Down:
        case Keys.S:
            y = 1;
            doMoveEle(x, y);
            eleChanged = true;
            break;
    }

    ...
}

Of course the arrow keys could not work, now we changed to the following:

Way 1: Simply set IsInputKey to true in PreviewKeyDown event, and keep all logic code in KeyDown event:

private void VectShapes_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
{
    switch (e.KeyCode)
    {
        case Keys.Down:
        case Keys.Up:
        case Keys.Right:
        case Keys.Left:
            e.IsInputKey = true;
            break;
    }
}

Way 2: Move all logic code from KeyDown event to PreViewKeyDown event:

private void VectShapes_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
{
    bool eleChanged = false;

    int x, y;

    x = y = 0;

    switch (e.KeyCode)
    {
        case Keys.Left:
        case Keys.A:
            x = -1;
            doMoveEle(x, y);
            eleChanged = true;
            break;
        case Keys.Right:
        case Keys.D:
            x = 1;
            doMoveEle(x, y);
            eleChanged = true;
            break;

        case Keys.Up:
        case Keys.W:
            y = -1;
            doMoveEle(x, y);
            eleChanged = true;
            break;

        case Keys.Down:
        case Keys.S:
            y = 1;
            doMoveEle(x, y);
            eleChanged = true;
            break;
    }

    ...
}