检测箭头键-同时检测多个键

本文关键字:检测 | 更新日期: 2023-09-27 18:26:55

我正在尝试制作一个简单的应用程序,让用户可以用箭头四处移动。到目前为止,我成功地让用户上下左右移动了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);
        }

问题是,我很想让用户也按对角线走。喜欢在同一时间向上和向右。我试图寻找一些解决方案,但不幸的是没有任何运气。我会尝试修改它,使左/右键转动/旋转,所以向上键的意思是"向前",而不是"向上"。但首先,我需要让两个键同时成为可能。

所以问题是,我如何才能做到,一次使用两个键,对角移动?

PS。Atm,我正在picturebox上移动一个椭圆,更改Point statek = new Point(250, 470);线,所以每次计时器滴答作响时,它都会检查X或Y是否发生了变化,并将其绘制在新的位置。经常滴答作响——这就是我目前试图实现实时运动的方式。这不会是任何复杂的应用程序。

检测箭头键-同时检测多个键

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

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

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

这允许您跟踪按下了哪些键,并决定哪些组合是有效的。

每个按键按下/按下事件触发一次。因此,在一个事件中检测两个键是不可能的,但您可以在事件之外的集合中跟踪这些信息。

使用GetKeyboardState的改进版本。这一次,计时器将调用一个函数,该函数将检查按下的键,构造ArrowsPressed枚举并调用函数以执行移动。如果您想使用其他键,请将其放入virtualKeyToArrowsPressedDictionary中。

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
}