C# tratando de capturar el evento KeyDown en un formulario


Estoy creando un juego pequeño, el juego se imprime en un panel en un formulario de windows. Ahora quiero capturar el evento keydown para ver si es las teclas de flecha que se ha pulsado, el problema sin embargo es que parece que no puedo capturarlo.

Permítanme explicar, en el formulario tengo 4 botones y varios otros controles y si el usuario, por ejemplo, presiona uno de los botones (para activar un evento de juego), entonces el botón tiene foco y no puedo capturar los movimientos con las teclas de flecha.

I probé algo como

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());
        }
    }

Y luego cuando se presionó la tecla de formulario hacia abajo, usé este

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

También he añadido keydown para los botones y los otros controles en el formulario de Windows, pero no estoy recibiendo ninguna respuesta de nuevo. He configurado un punto de interrupción dentro de la función para ver si se está llamando, pero ese punto de interrupción nunca se activa?

¿Alguna idea?

Lo más óptimo era tener un evento de KeyDown general que se desencadena (independientemente del control que actualmente tiene foco) y luego llama al método KeyDown.

Author: Patrick, 2009-08-19

4 answers


Override IsInputKey behaviour


Debe anular el comportamiento IsInputKey para informar que desea que la tecla de flecha derecha se trate como una tecla de entrada y no como una tecla de comportamiento especial. Para ello debe anular el método para cada uno de sus controles. Te aconsejaría crear tus Botones ganados, digamos myButton

La siguiente clase crea un botón personalizado que anula el método IsInputKey para que la tecla de flecha derecha no se trata como una llave especial. Desde allí se puede hacer fácilmente para las otras teclas de flecha o cualquier otra cosa.

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

Después, puedes tratar tu evento keyDown event en cada botón diferente o en el propio formulario:

En el Método KeyDown de los Botones, intente establecer estas propiedades:

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

OR O {

Maneje el comportamiento común en la forma: (no establezca e.Handled = true; en los botones)

private void Form1_KeyDown(object sender, KeyEventArgs e)
{
    //DoSomething();
}
 17
Author: Luis Filipe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-11-26 15:42:20

¿Ha establecido la KeyPreview propiedad de la forma a true? Eso hará que el formulario obtenga una" primera mirada " a los eventos clave.

Actualizar: hacer que esto funcione correctamente cuando un Button tiene foco parece ser un poco complicado. El control de botón intercepta las pulsaciones de la tecla de flecha y mueve el foco al control siguiente o anterior en el orden de pestañas de manera que el KeyDown, KeyUp y KeyPress los eventos no se plantean. Sin embargo, el evento PreviewKeyDown se plantea, por lo que puede ser usado:

private void Form_KeyDown(object sender, KeyEventArgs e)
{
    e.Handled = ProcessKeyDown(e.KeyCode);
}

// event handler for the PreViewKeyDown event for the buttons
private void ArrowButton_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
{
    ProcessKeyDown(e.KeyCode);

}

private bool ProcessKeyDown(Keys keyCode)
{
    switch (keyCode)
    {
        case Keys.Up:
            {
                // act on up arrow
                return true;
            }
        case Keys.Down:
            {
                // act on down arrow
                return true;
            }
        case Keys.Left:
            {
                // act on left arrow
                return true;
            }
        case Keys.Right:
            {
                // act on right arrow
                return true;
            }
    }
    return false;
}

Aún así, el enfoque se mueve de una manera bastante fea...

 29
Author: Fredrik Mörk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-08-19 12:56:13

Creo que la forma más fácil de resolver este problema es sobrescribiendo el método ProcessCmdKey() del formulario. De esa manera, su lógica de manejo de claves se ejecuta sin importar qué control tenga foco en el momento de presionar las teclas. Además de eso, incluso puede elegir si el control enfocado obtiene la clave después de procesarla (devolver false) o no (devolver true).
Tu pequeño ejemplo de juego podría reescribirse así:

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);
}
 16
Author: RudolfW,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-08-12 09:17:20
public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
        KeyPreview = true;
        KeyDown += new KeyEventHandler(Form1_KeyDown);
    }

    void Form1_KeyDown(object sender, KeyEventArgs e)
    {
        System.Diagnostics.Debug.Write(e.KeyCode);
    }
}
 7
Author: dnkira,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-10-16 17:35:18