C#试图捕获表单上的KeyDown事件

我正在创建一个小游戏,游戏被打印到Windows窗体上的面板上。 现在我想捕获keydown事件以查看它是否已被按下的箭头键,但问题是我似乎无法捕获它。

让我解释一下,在表格上我有4个按钮和各种其他控件,如果用户例如按下其中一个按钮(触发游戏事件),那么按钮有焦点,我无法用箭头键捕捉动作。

我尝试过类似的东西

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

然后当按下表单按键事件时,我使用了这个

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

我还为Windows窗体上的按钮和各种其他控件添加了keydown,但我没有收到任何回复。 我在函数内部设置了一个断点,看它是否被调用,但该断点永远不会触发?

有任何想法吗?

最优化的是具有触发的通用KeyDown事件(无论当前具有什么焦点的控件),然后调用KeyDown方法。


覆盖IsInputKey行为


您必须覆盖IsInputKey行为,以通知您希望将右箭头键视为InputKey而不是特殊行为键。 为此,您必须覆盖每个控件的方法。 我建议你创建你赢得的按钮,让我们说MyButton

下面的类创建一个自定义Button,它覆盖IsInputKey方法,因此右箭头键不会被视为特殊键。 从那里你可以轻松地为其他箭头键或其他任何东西。

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

之后,您可以在每个不同的Button或表单本身中处理您的keyDown事件事件:

在按钮的KeyDown方法中尝试设置这些属性:

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

– 要么 –

处理表单中的常见行为:(不要设置e.Handled = true;在按钮中)

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

您是否将表单的KeyPreview属性设置为true ? 这将使表单在关键事件中获得“第一眼”。

更新:Button具有焦点时,使其正常工作似乎有点棘手。 Button控件截取箭头键,并以一种方式将焦点移动到Tab键顺序中的下一个或上一个控件,以便不引发KeyDownKeyUpKeyPress事件。 但是,会引发PreviewKeyDown事件,因此可以使用:

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

尽管如此,焦点还是以一种相当丑陋的方式移动……

我相信解决此问题的最简单方法是重写表单的ProcessCmdKey()方法。 这样,无论在按键时哪个控件都有焦点,您的键处理逻辑都会被执行。 除此之外,您甚至可以选择在您处理之后焦点控件是否获得键(返回false)或不返回(返回true)。
您的小游戏示例可以像这样重写:

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