2009-08-19 29 views
24

Estoy creando un juego pequeño, el juego se imprime en un panel en un formulario de Windows. Ahora quiero capturar el evento de pulsación para ver si son las teclas de flecha que se han presionado, pero el problema es que parece que no puedo capturarlo.C# tratando de capturar el evento KeyDown en un formulario

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), el botón tiene foco y no puedo capturar los movimientos con las teclas de flecha.

he intentado algo así 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 la tecla formulario abajo evento fue presionado, he utilizado este

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

También he añadido keydown para los botones y los demás controles de la Windows forma, pero no estoy recibiendo ninguna respuesta. 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 dispara?

¿Alguna idea?

Lo más óptimo fue tener un evento KeyDown general que desencadena (independientemente de qué control tenga foco actualmente) y luego llama al método KeyDown.

Respuesta

17

Anulación IsInputKey comportamiento


Debe anular el comportamiento IsInputKey para informar que desea el derecho Ar clave de fila para ser tratada como una clave de entrada y no como una tecla de comportamiento especial. Para eso debes anular el método para cada uno de tus controles. Yo aconsejaría al usuario crear sus botones de ganado, digamos MiBoton

La clase siguiente se crea un botón personalizado que anula el métodoIsInputKey de modo que la tecla de flecha derecha no se trata como una llave especial. Desde allí, puede hacer fácilmente 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, usted puede tratar su caso evento keyDown en cada botón diferente o en el propio formulario:

En los botones KeyDown Método tratar de establecer estas propiedades:

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

- O -

maneje el comportamiento común en el siguiente formato: (no configure e.Handled = verdadero; en los botones)

private void Form1_KeyDown(object sender, KeyEventArgs e) 
{ 
    //DoSomething(); 
} 
+1

Es semi-trabajo, ahora recibo el evento de tecla, pero cuando presiono los botones, aún se enfocan y luego deja de funcionar a menos que presione la tecla de flecha superior hasta que pasa por todos y pierden el foco. – Patrick

+0

¿Cómo atrapa los eventos KeyDown "Keys.Left" y "Keys.Right"? –

+0

Edité mi respuesta para referirme al método IsInputKey –

29

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

Actualización: haciendo que esto funcione correctamente cuando un Button tiene foco parece ser un poco complicado. El control de botón intercepta las teclas de flecha y mueve el foco al control siguiente o anterior en el orden de tabulación de manera que los eventos KeyDown, KeyUp y KeyPress no se generan. Sin embargo, el evento PreviewKeyDown se eleva, por lo que se pueden utilizar:

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

Sin embargo, el foco se mueve de una manera bastante feo ...

+0

Es semi-trabajo, ahora consigo el evento KeyDown pero cuando pulso los botones, todavía se convierten en la concentración y luego se detiene a trabajar a menos pulso el la tecla de la flecha superior hasta que pasa por todos y pierden el foco. – Patrick

+0

@Patrick: sí, las teclas de flecha y el control de botón parecen tener una relación muy estrecha. He actualizado mi respuesta presionándola un paso adelante. –

7
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); 
    } 
} 
+1

No sabes que tu respuesta ahorra mucho tiempo mía. Muchas gracias. –

+0

Debería ser 'KeyPreview = true;' que hace que el KeyDown se active –

16

creo que la forma más fácil de resolver este problema es a través de la sustitución del método ProcessCmdKey() del formulario. De esta forma, la lógica de manejo de teclas se ejecuta independientemente de qué control tenga foco en el momento de la pulsación de tecla. Además de eso, incluso puede elegir si el control enfocado obtiene la clave después de procesarla (devolver falsa) o no (devolver verdadera).
Su pequeño juego de ejemplo 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); 
} 
+0

Es genial, pero la clave de espacio no procesa – Singlet

+2

Gran solución. Captura todas las pulsaciones de teclas. Incluso el espacio. – Kibbee

+0

Esta es la forma más fácil de resolver esos problemas, y funcionó perfectamente para mí también. –

Cuestiones relacionadas