检测箭头键 - 一次
我试图让简单的应用程序多个按键,让用户能够走动箭头。到目前为止,我设法让用户上下左右重写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个键来对角移动?
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属性,让形式收到的情况下,密钥的子控件想偷他们;
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结构握住你的地位测试的所有跟踪键和方向移动一点上,他们表示,使用GetKeyboardState
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状态的所有键的某种类型的列表。
这允许您跟踪哪些按键被按下并决定哪些组合是有效的。
每个事件触发一次按键向下/向上事件。因此,在一个事件中检测两个键是不可能的,但您可以在事件范围外的集合中跟踪此信息。
改进版这一个围绕定时器的Wi时间。将调用一个函数来检查按下的键,构造ArrowsPressed枚举并调用一个函数来执行移动。如果你想使用一些其他的键把它放在virtualKeyToArrowsPressed Dictionary中。
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
}
这是一个很好的答案。 – 2012-03-06 01:13:13
不起作用,关键停止重复。计时器是必需的。 – 2012-03-06 01:29:14
@Hans是的,你是绝对正确的。 Windows为最后一个按键发送WM_KEYDOWN消息。当这个键被释放时,移动停止。在这种情况下,计时器肯定会有所帮助,但如果使用计时器,它将支付Pinvoke用于GetKeyboardState。 – 2012-03-06 02:20:14