validate - keypress c# visual studio
C#tratando de capturar el evento KeyDown en un formulario (4)
Estoy creando un juego pequeño, el juego se imprime en un panel en una ventana. Ahora quiero capturar el evento keydown para ver si se presionaron las teclas de flecha, sin embargo, el problema 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 del juego), entonces el botón tiene el enfoque y no puedo capturar los movimientos con las teclas de flecha .
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ó el evento de tecla de formulario hacia abajo, usé esto
private void MainForm_KeyDown(object sender, KeyEventArgs e)
{
KeyDown(e);
}
También agregué keydown para los botones y varios otros controles en el formulario de Windows, 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 activa?
¿Algunas ideas?
Lo más óptimo fue tener un evento KeyDown general que se dispare (independientemente del control que tenga el foco actualmente) y luego llame al método KeyDown.
¿Ha establecido la propiedad KeyPreview
del formulario en true
? Eso hará que el formulario obtenga un "primer vistazo" a los eventos clave.
Actualización: hacer que esto funcione correctamente cuando un Button
tiene enfoque parece ser un poco complicado. El control Button intercepta las teclas de flecha presionando y moviendo el foco al control siguiente o anterior en el orden de tabulación de manera que los KeyDown
, KeyUp
y KeyPress
no se KeyUp
. Sin embargo, el evento PreviewKeyDown
se PreviewKeyDown
, por lo que se puede 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;
}
Aún así, el enfoque se mueve de una manera bastante fea ...
Anular el comportamiento de IsInputKey
Debe anular el comportamiento de IsInputKey para informar que desea que la tecla de flecha derecha se trate como una InputKey y no como una clave de comportamiento especial. Para eso debes anular el método para cada uno de tus controles. Te aconsejo que crees tus botones ganados, digamos MyButton
La clase a continuación crea un botón personalizado que anula el método IsInputKey para que la tecla de flecha derecha no se trate como una tecla especial. Desde allí puedes hacerlo 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, puede tratar el evento de evento keyDown en cada botón diferente o en el 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();
}
- O -
manejar el comportamiento común en el formulario: (no establezca e.Handled = true; en los botones)
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
//DoSomething();
}
Creo que la forma más fácil de resolver este problema es anular el método ProcessCmdKey () del formulario. De esa manera, su lógica de manejo de claves se ejecuta sin importar qué control tenga el enfoque al momento de presionar una tecla. Además de eso, incluso puedes elegir si el control enfocado obtiene la clave después de procesarla (devuelve falso) o no (retorna verdadero).
Tu pequeño ejemplo de juego podría ser reescrito 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);
}
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);
}
}