检测箭头键 - 一次多个键

时间:2012-03-05 23:27:27

标签: c# visual-studio visual-studio-2010 key

我正在尝试制作简单的应用,让用户可以用箭头移动。到目前为止,我设法让用户向上,向下,向左和向右移动重写ProcessCmdKey()方法。

protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
        {
            if (keyData == Keys.Up)
            {
                statek.Y--;
                return true;
            }
            if (keyData == Keys.Left)
            {
                statek.X--;
                return true;
            }
            if (keyData == Keys.Right)
            {
                statek.X++;
                return true;
            }
            if (keyData == Keys.Down)
            {
                statek.Y++;
                return true;
            }
            return base.ProcessCmdKey(ref msg, keyData);
        }

问题是,我很乐意让用户对角走。同时向上和向右。我试图寻找一些解决方案,但遗憾的是没有运气。 我将尝试修改它,使左/右键转动/旋转,因此向上键表示“向前”,而不是“向上”。但首先,我需要一次制作2个键。

所以问题是,我如何能够一次使用2个键来对角移动?

PS。 Atm,我在图片框上移动一个椭圆,更改Point statek = new Point(250, 470);线,所以每次定时器滴答,它会检查X或Y是否改变,并在新的位置绘制它。通常滴答声 - 这就是我现在试图实现实时运动的方式。这不会是任何复杂的应用程序。

3 个答案:

答案 0 :(得分:2)

您需要保留当前处于Key_Down状态的所有键的某种类型的列表。

这使您可以跟踪按下的键,并确定哪些组合有效。

每个按键向下/向上事件触发一次。因此,无法在一个事件中检测到两个键,但您可以在事件之外的集合中跟踪此信息。

答案 1 :(得分:2)

首先创建位枚举以保持箭头键状态:

[Flags]
enum ArrowsPressed
{
    None = 0x00,
    Left = 0x01,
    Right = 0x02,
    Up = 0x04,
    Down = 0x08,
    All = 0x0F
}

然后成员跟踪状态和改变它的功能;

ArrowsPressed arrowsPressed;

void ChangeArrowsState(ArrowsPressed changed, bool isPressed)
{
    if (isPressed)
    {
        arrowsPressed |= changed;
    }
    else
    {
        arrowsPressed &= ArrowsPressed.All ^ changed;
    }
}

覆盖KeyDown和KeyUp(不要忘记将表单的KeyPreview属性设置为true,以便在子控件想要窃取它时让表单接收密钥;

protected override void OnKeyDown(KeyEventArgs e)
{
    base.OnKeyDown(e);
    switch (e.KeyCode)
    {
        case Keys.Down:
            ChangeArrowsState(ArrowsPressed.Down, true);
            break;
        case Keys.Up:
            ChangeArrowsState(ArrowsPressed.Up, true);
            break;
        case Keys.Left:
            ChangeArrowsState(ArrowsPressed.Left, true);
            break;
        case Keys.Right:
            ChangeArrowsState(ArrowsPressed.Right, true);
            break;
        default:
            return;
    }
    HandleArrows();
    e.Handled = true;
}
protected override void OnKeyUp(KeyEventArgs e)
{
    base.OnKeyUp(e);
    switch (e.KeyCode)
    {
        case Keys.Down:
            ChangeArrowsState(ArrowsPressed.Down, false);
            break;
        case Keys.Up:
            ChangeArrowsState(ArrowsPressed.Up, false);
            break;
        case Keys.Left:
            ChangeArrowsState(ArrowsPressed.Left, false);
            break;
        case Keys.Right:
            ChangeArrowsState(ArrowsPressed.Right, false);
            break;
        default:
            return;
    }
    e.Handled = true;
}

最后,使用Point结构来保持你的位置测试所有被跟踪的键并按照它们指示的方向移动点;

Point position;
private void HandleArrows()
{
    if ((arrowsPressed & ArrowsPressed.Down) != ArrowsPressed.None)
    {
        position.Y++;
    }
    if ((arrowsPressed & ArrowsPressed.Up) != ArrowsPressed.None)
    {
        position.Y--;
    }
    if ((arrowsPressed & ArrowsPressed.Left) != ArrowsPressed.None)
    {
        position.X--;
    }
    if ((arrowsPressed & ArrowsPressed.Right) != ArrowsPressed.None)
    {
        position.X++;
    }
    //  Do whatever is needed using position
}

答案 2 :(得分:1)

使用GetKeyboardState改进版本。此时计时器将调用一个函数,该函数将检查按下的键,构造ArrowsPressed枚举并调用函数 执行运动。如果你想使用其他一些键把它放在virtualKeyToArrowsPressed字典中。

const int VK_LEFT = 0x25;
const int VK_UP = 0x26;
const int VK_RIGHT = 0x27;
const int VK_DOWN = 0x28;

[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool GetKeyboardState(byte[] lpKeyState);

byte[] keys = new byte[256];

[Flags]
enum ArrowsPressed
{
    None = 0x00,
    Left = 0x01,
    Right = 0x02,
    Up = 0x04,
    Down = 0x08,
    All = 0x0F
}
Dictionary<int, ArrowsPressed> virtualKeyToArrowsPressed = new Dictionary<int, ArrowsPressed>
{
    { VK_LEFT, ArrowsPressed.Left },
    { VK_RIGHT, ArrowsPressed.Right },
    { VK_UP, ArrowsPressed.Up },
    { VK_DOWN, ArrowsPressed.Down },
};

protected override void OnLoad(EventArgs e)
{
    base.OnLoad(e);

    timer1.Tick += timer1_Tick;
    timer1.Interval = 100;
    timer1.Start();
}

void timer1_Tick(object sender, EventArgs e)
{
    if (GetKeyboardState(keys))
    {
        ArrowsPressed arrowsPressed = ArrowsPressed.None;
        foreach (KeyValuePair<int, ArrowsPressed> kvp in virtualKeyToArrowsPressed)
        {
            if ((keys[kvp.Key] & 0x80) != 0)
            {
                arrowsPressed |= kvp.Value;
            }
        }
        if (arrowsPressed != ArrowsPressed.None)
        {
            HandleArrows(arrowsPressed);
        }
    }
}

Point position;
private void HandleArrows(ArrowsPressed arrowsPressed)
{
    if ((arrowsPressed & ArrowsPressed.Down) != ArrowsPressed.None)
    {
        position.Y++;
    }
    if ((arrowsPressed & ArrowsPressed.Up) != ArrowsPressed.None)
    {
        position.Y--;
    }
    if ((arrowsPressed & ArrowsPressed.Left) != ArrowsPressed.None)
    {
        position.X--;
    }
    if ((arrowsPressed & ArrowsPressed.Right) != ArrowsPressed.None)
    {
        position.X++;
    }
    //  Do whatever is needed using position
}