响应多个KeyDown事件

我正在制作一个简单的WinForm赛车游戏。 我有两个对象 – 汽车,当按下键时它们会在窗体上移动(Form1KeyDown_Event)。

唯一的事情是,当一个玩家按下一个键时,另一个玩家不能按下他的键(没有任何反应)。 但是当第一个玩家释放钥匙时,第二个玩家可以按下他的钥匙并且通常控制他的车。

我怎样才能同时听两个玩家的按键? 我应该使用线程并让每辆车都在自己的线程上吗?

下面是一个简单的示例,说明如何使用keyup和keydown事件同时侦听多个键。

using System; using System.Collections.Generic; using System.Windows.Forms; namespace WinFormTest { public partial class Form1 : Form { private readonly IDictionary downState; public Form1() { InitializeComponent(); downState = new Dictionary(); downState.Add(Keys.W, false); downState.Add(Keys.D, false); KeyDown += remember; KeyUp += forget; } protected override void OnLoad(EventArgs e) { base.OnLoad(e); Timer timer = new Timer() { Interval = 100 }; timer.Tick += updateGUI; timer.Start(); } private void remember(object sender, KeyEventArgs e) { downState[e.KeyCode] = true; } private void forget(object sender, KeyEventArgs e) { downState[e.KeyCode] = false; } private void updateGUI(object sender, EventArgs e) { label1.Text = downState[Keys.W] ? "Forward" : "-"; label2.Text = downState[Keys.D] ? "Right" : "-"; } } } 

您可能希望调查更低级别并使用Windows挂钩来检测键盘事件。 这需要P / Invoking到本机方法,但非常简单。 你想要的钩子是WH_LL_KEYBOARD。 详细信息可以在pinvoke.net找到。

你需要一些样板,但它与你可以合理期望得到的键盘事件一样接近:

 [StructLayout(LayoutKind.Sequential)] public struct KBDLLHOOKSTRUCT { public uint vkCode; public uint scanCode; public uint flags; public uint time; public IntPtr dwExtraInfo; } public delegate IntPtr LowLevelKeyboardProc(int, IntPtr, KBDLLHOOKSTRUCT); [DllImport("kernel32.dll")] public static extern uint GetCurrentThreadId(); [DllImport("kernel32.dll", SetLastError = true)] public static extern IntPtr GetModuleHandle(string lpModuleName); [DllImport("user32.dll", SetLastError = true)] public static extern bool UnhookWindowsHookEx(IntPtr hhk); [DllImport("user32.dll", SetLastError = true)] public static extern IntPtr SetWindowsHookEx(int idhook, LowLevelKeyboardProc proc, IntPtr hMod, uint threadId); [DllImport("user32.dll")] static extern int CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, ref KBDLLHOOKSTRUCT lParam); public static IntPtr SetHook(LowLevelKeyboardProc proc) { using (var curProc = Process.GetCurrentProcess()) using (var curMod = curProc.MainModule) { return SetWindowsHookEx(WH_KEYBOARD_LL, proc, GetModuleHandle(curMod.ModuleName), 0u); } } public IntPtr MyKeyboardHook(int code, IntPtr wParam, ref KBDLLHOOKSTRUCT keyboardInfo) { if (code < 0) { return CallNextHookEx(IntPtr.Zero, wParam, ref keyboardInfo); } // Do your thing with the keyboard info. return CallNextHookEx(IntPtr.Zero, code, wParam, ref keyboardInfo); } 

确保在应用程序停止需要时取消挂钩处理程序。 KBDLLHOOKSTRUCT封装了Windows将为您提供的有关键盘事件的所有信息; 其成员的详细信息可以在MSDN上找到 。

这种钩子的一个细节就是它在注册它的线程上执行,所以请确保你注意到它,如果它要做长期运行的话,不要在UI线程上设置它。