检测箭头键-同时检测多个键
本文关键字:检测 | 更新日期: 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
}