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

Я также добавил keydown для кнопок и различных других элементов управления в форме windows, но я не получаю никакого ответа. Я установил точку останова внутри функции, чтобы увидеть, вызывается ли она, но эта точка останова никогда не срабатывает?

какие идеи?

наиболее оптимальным было иметь общий KeyDown событие, которое запускает (независимо от того, какой элемент управления в настоящее время имеет фокус), а затем вызывает метод KeyDown.

4 ответов



переопределить 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 event в каждой другой кнопке или в самой форме:

в методе 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 фокус, кажется, немного сложнее. Кнопка управления перехватывает нажатие клавиши со стрелкой и перемещает фокус на следующий или предыдущий элемент управления в порядке табуляции таким образом, чтобы KeyDown, KeyUp и 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;
}

тем не менее, фокус перемещается довольно уродливым образом...


Я считаю, что самый простой способ решения этой проблемы - переопределение метода ProcessCmdKey () формы. Таким образом, ваша логика обработки ключей выполняется независимо от того, какой элемент управления имеет фокус во время нажатия клавиши. Кроме того, вы даже можете выбрать, получает ли сфокусированный элемент управления ключ после его обработки (return false) или нет (return 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);
    }
}