我应该使用 DirectInput 还是 Windows 消息循环?
Posted
技术标签:
【中文标题】我应该使用 DirectInput 还是 Windows 消息循环?【英文标题】:Should I use DirectInput or Windows message loop? 【发布时间】:2011-01-11 00:51:21 【问题描述】:我正在开发 C++ DirectX 2D 游戏,我需要键盘和鼠标输入。 ***说:
Microsoft 建议新应用程序使用 Windows 消息循环而不是 DirectInput 进行键盘和鼠标输入
那么我应该如何使用它呢? 我有一个 GameScreen 类负责绘图和更新(游戏逻辑),我在 Windows 消息循环中调用 Draw 和 Update 方法。
谢谢
【问题讨论】:
【参考方案1】:如果游戏只有一个窗口,那么据我所知,区别纯粹是口味问题。但是,如果您拥有(或计划拥有,或不能肯定地排除将来拥有)多个窗口的选项,那么 Windows 消息传递可能会令人厌烦。
问题在于,默认情况下,键盘/鼠标消息仅路由到当前焦点所在的窗口,并且通常在您希望能够切换焦点的游戏中(到高分视图、雷达视图上的敌人或其他)和仍然保持交互性。简单的解决方案是针对每个需要键盘/鼠标输入来直接查询它的模块,而不是依赖消息转发 - 因此是 DirectInput。
当然,我不能对你的具体情况说太多 - 只是我的 2c。
【讨论】:
键盘和鼠标事件不会转到焦点窗口。 由您的消息泵(这就是 DispatchMessage 所做的)将键盘事件发送到焦点窗口。鼠标事件转到光标下的窗口。 对。谢谢!我最初只用键盘评论,然后才将它“固定”到键盘/鼠标..【参考方案2】:XInput 绝对是要走的路。低延迟输入对游戏至关重要,而 XInput(在新的 DirectXSDK 中替代 DirectInput)正是为这些用例而设计的。
您还可以开箱即用地支持游戏控制器、操纵杆等。
【讨论】:
DirectInput 不会降低键盘和鼠标事件的延迟。但如果您以后想要支持操纵杆等,它确实为您提供了更一致的输入模型。 你说得对,但我的意思是 DirectInput(和 XInput,它是 DInputs 的后继者)的延迟比 Windows 消息低。 但不适用于键盘和鼠标输入。 DirectInput 只是针对键盘和鼠标的 Win32 API 的封装。 这不是真的。您对 DInput 1.0 是正确的,因为这是对 win32 输入的简单包装,但由于 2.0 DInput 直接与驱动程序对话。 Windows 消息系统在将输入数据传递给应用程序(WM_CLICK、WM_DOUBLECLICK 等)之前对输入数据进行预处理,处理所有焦点要求等。这是延迟差异的主要来源。 顺便说一句。您可以在“Direct X 输入 -> 直接输入 -> 了解 DirectInput”中的 DirectX SDK 文档中找到对我声明的引用【参考方案3】:由于您几乎必须运行消息泵才能拥有一个窗口,因此您也可以使用该泵来处理键盘和鼠标输入。是否将键盘事件交给子窗口完全取决于您的泵,如果您愿意,可以在泵中处理它们。
您的典型消息泵如下所示:
while (GetMessage(&msg, NULL, 0, 0))
if (WM_QUIT == msg.message)
break;
TranslateMessage(&msg); // post a WM_CHAR message if this is a WM_KEYDOWN
DispatchMessage(&msg); // this sends messages to the msg.hwnd
对于游戏,您的泵可能看起来更像这样
while (true)
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE | PM_NOYIELD))
bool fHandled = false;
if (msg.message >= WM_MOUSEFIRST && msg.message <= WM_MOUSELAST)
fHandled = MyHandleMouseEvent(&msg);
else if (msg.message >= WM_KEYFIRST && msg.message <= WM_KEYLAST)
fHandled = MyHandleKeyEvent(&msg);
else if (WM_QUIT == msg.message)
break;
if ( ! fHandled)
TranslateMessage(&msg);
DispatchMessage(&msg);
else
// if there are no more messages to handle right now, do some
// game slice processing.
//
当然,您的实际泵可能会比这更复杂,可能使用MsgWaitForMultipleObjects
,这样即使没有要处理的消息,您也可以定期唤醒,但在有消息时立即唤醒。
【讨论】:
我想知道为什么不应该使用 DirectInput。谢谢 亚历克斯在***.com/questions/2165230/…回答【参考方案4】:是的,MSDN 帖子是正确的。使用 Windows 消息,您可以使用多语言支持(对于用户可能使用的任何类型的键盘)/用户的个人设置(鼠标右键而不是左键)等。您必须丢弃这些才能使用 DirectInput/XInput . 仅将这 2 个用于游戏手柄/操纵杆支持。其余的只需使用 Windows 消息。
关于细节,我同意 John Knoeller 的回答。
【讨论】:
【参考方案5】:DirectInput 已被弃用,原因很充分。据我所知,它创建了一个额外的线程并仅查询 Windows 的Raw Input 接口。为了获得最佳性能,我会直接使用原始输入。
如果性能对您来说不是问题(我猜这是在当前硬件上玩 2D 游戏的情况),请遵循 Microsoft 的建议并使用 John Knoeller 所述的窗口消息。
【讨论】:
您能否进一步证实“仅查询 Windows 的原始输入界面”(也许有参考)?【参考方案6】:仅供参考:关于 John Knoeller 的回答...一个简单的消息泵看起来像这样:
while (GetMessage(&msg, NULL, 0, 0))
TranslateMessage(&msg);
DispatchMessage(&msg);
他包含的 WM_QUIT 测试永远不会为真,因为 GetMessage 在收到 WM_QUIT 时返回零。但是,需要在 PeekMessage 循环中测试 WM_QUIT ,因为无论是否返回消息,PeekMessage 都会返回 true/false。由于 GetMessage 会阻塞直到返回消息,所以它可以有不同的返回值。
【讨论】:
【参考方案7】:特殊情况下只能使用directinput
与 getmessage 一起使用的 Windows 消息循环的好处是它使用 0% 的 cpu 使用率。如果您正在执行非处理器密集型操作,例如等待来自用户的密钥、从用户那里收集数据(例如在数据库或税务程序中,甚至是文字处理器),那么将 Windows 消息与 getmessage 一起使用是有意义的。我上面所有的程序日期都是用户按键的过程。
Windows 消息循环处理键所需的全部内容就是切换到该程序。鼠标甚至不需要在窗口中。
特殊情况-使用直接输入
如果您需要: 1)知道何时按下和释放键。您也可能不希望将重复键检测为按键。 2) 切换其他程序时在后台处理keys。
如果以上任何一个为真,则使用直接输入。
如果您只是从用户那里收集数据,那么您将需要使用 sleep 命令来暂停程序的执行。如果程序只是坐在那里等待用户的密钥,您希望程序在任务管理器中的 cpu 使用率为 0%。
使用睡眠功能使程序进入睡眠状态,直到您想轮询直接输入的键。
因此,如果您正在执行从用户那里收集密钥的简单普通任务,如您所见,直接输入只会浪费编程时间。
【讨论】:
以上是关于我应该使用 DirectInput 还是 Windows 消息循环?的主要内容,如果未能解决你的问题,请参考以下文章