Alex Rivera | Logout

C# trying to capture the KeyDown event on a form

Asked 2009-08-19T09:06:53.863
27

I am creating a small game, the game is printed onto a panel on a windows form. Now i want to capture the keydown event to see if its the arrow keys that has been pressed, the problem however is that i can't seem to capture it.

Let me explain, on the form i have 4 buttons and various other controls and if the user for instance press one of the buttons (to trigger a game event) then the button has focus and i can't capture the movements with the arrow keys.

I tried something like

private void KeyDown(KeyEventArgs e)
    {
        if (e.KeyCode == Keys.Left)
        {
            game.MovePlayer(DonutWarsLibrary.GameObjects.Direction.E);
            game.DrawObjects(panel1.CreateGraphics());
        }
        else if (e.KeyCode == Keys.Right)
        {
            game.MovePlayer(DonutWarsLibrary.GameObjects.Direction.W);
            game.DrawObjects(panel1.CreateGraphics());
        }
        else if (e.KeyCode == Keys.Up)
        {
            game.MovePlayer(DonutWarsLibrary.GameObjects.Direction.N);
            game.DrawObjects(panel1.CreateGraphics());
        }
        else if (e.KeyCode == Keys.Down)
        {
            game.MovePlayer(DonutWarsLibrary.GameObjects.Direction.S);
            game.DrawObjects(panel1.CreateGraphics());
        }
    }

and then when the form key down event was pressed, i used this

private void MainForm_KeyDown(object sender, KeyEventArgs e)
    {
        KeyDown(e);
    }

I also added keydown for the buttons and the various other controls on the windows form, but i am not getting any response back. I have setup a breakpoint inside the function to see if it's being called, but that breakpoint never triggers?

Any ideas?

The most optimal was to have a general KeyDown event that triggers (regardless of what control that currently has focus) and then calls the KeyDown method.

Edit
Report

2 Answers

19

I believe the easiest way of solving this problem is through overriding the ProcessCmdKey() method of the form. That way, your key handling logic gets executed no matter what control has focus at the time of keypress. Beside that, you even get to choose whether the focused control gets the key after you processed it (return false) or not (return true).
Your little game example could be rewritten like this:

protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
    if (keyData == Keys.Left)
    {
        MoveLeft(); DrawGame(); DoWhatever();
        return true; //for the active control to see the keypress, return false
    }
    else if (keyData == Keys.Right)
    {
        MoveRight(); DrawGame(); DoWhatever();
        return true; //for the active control to see the keypress, return false
    }
    else if (keyData == Keys.Up)
    {
        MoveUp(); DrawGame(); DoWhatever();
        return true; //for the active control to see the keypress, return false
    }
    else if (keyData == Keys.Down)
    {
        MoveDown(); DrawGame(); DoWhatever();
        return true; //for the active control to see the keypress, return false
    }
    else
        return base.ProcessCmdKey(ref msg, keyData);
}
answered 2010-08-12T09:17:20.657
17

Override IsInputKey behaviour


You must override the IsInputKey behavior to inform that you want the Right Arrow key to be treated as an InputKey and not as a special behavior key. For that you must override the method for each of your controls. I would advise you to create your won Buttons, let's say MyButton

The class below creates a custom Button that overrides the IsInputKey method so that the right arrow key is not treated as a special key. From there you can easily make it for the other arrow keys or anything else.

    public partial class MyButton : Button
    {
        protected override bool IsInputKey(Keys keyData)
        {
            if (keyData == Keys.Right)
            {
                return true;
            }
            else
            {
                return base.IsInputKey(keyData);
            }
        }
    }

Afterwards, you can treat your keyDown event event in each different Button or in the form itself:

In the Buttons' KeyDown Method try to set these properties:

private void myButton1_KeyDown(object sender, KeyEventArgs e)
{
  e.Handled = true;
  //DoSomething();
}

-- OR --

handle the common behaviour in the form: (do not set e.Handled = true; in the buttons)

private void Form1_KeyDown(object sender, KeyEventArgs e)
{
    //DoSomething();
}
answered 2009-08-19T09:22:33.347

Your Answer