web-dev-qa-db-ja.com

フォームのKeyDownイベントをキャプチャしようとするC#

私は小さなゲームを作成しています。ゲームはWindowsフォームのパネルに印刷されます。今、キーダウンイベントをキャプチャして、押された矢印キーがあるかどうかを確認したいのですが、問題はそれをキャプチャできないように見えることです。

フォームに4つのボタンとさまざまなコントロールがあり、たとえばユーザーがボタンの1つを押して(ゲームイベントをトリガーする)場合、ボタンにフォーカスがあり、矢印キーで動きをキャプチャできません。

私は次のようなものを試しました

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

また、ボタンやその他のさまざまなウィンドウフォームのコントロールにキーダウンを追加しましたが、応答がありません。関数内にブレークポイントを設定して、呼び出されるかどうかを確認しましたが、そのブレークポイントはトリガーされませんか?

何か案は?

最も最適なのは、(現在フォーカスを持っているコントロールに関係なく)トリガーし、その後KeyDownメソッドを呼び出す一般的なKeyDownイベントを持つことです。

25
Patrick

上書きIsInputKey動作


IsInputKey動作をオーバーライドして、右矢印キーを特別な動作キーとしてではなく、InputKeyとして扱うことを通知する必要があります。そのためには、各コントロールのメソッドをオーバーライドする必要があります。勝ったボタンを作成することをお勧めします。たとえば、MyButton

以下のクラスは、右矢印キーが特別なキーとして扱われないように、IsInputKeyメソッドをオーバーライドするカスタムボタンを作成します。そこから、他の矢印キーまたはその他のものを簡単に作成できます。

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

その後、異なるボタンまたはフォーム自体でkeyDownイベントイベントを処理できます。

ボタンのKeyDownメソッドで、これらのプロパティを設定してみてください。

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

-OR-

フォームの一般的な動作を処理します:(ボタンにe.Handled = true;を設定しないでください)

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

フォームの KeyPreview プロパティをtrueに設定しましたか?これにより、フォームは主要なイベントを「最初に見る」ことができます。

更新:Buttonにフォーカスがあるときにこれを適切に動作させるのは少し難しいようです。 Buttonコントロールは、矢印キーの押下をインターセプトし、KeyDownKeyUpおよびKeyPressイベントが発生しないように、タブ順序で次または前のコントロールにフォーカスを移動します発生しました。ただし、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;
}

それでも、焦点はかなりい方法で動きます...

29
Fredrik Mörk

この問題を解決する最も簡単な方法は、フォームの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);
}
17
RudolfW
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
dnkira