【问题标题】:Should I use DirectInput or Windows message loop?我应该使用 DirectInput 还是 Windows 消息循环?
【发布时间】:2011-01-11 00:51:21
【问题描述】:

我正在开发 C++ DirectX 2D 游戏,我需要键盘和鼠标输入。
维基百科说:

Microsoft 建议新应用程序使用 Windows 消息循环而不是 DirectInput 进行键盘和鼠标输入

那么我应该如何使用它呢?
我有一个 GameScreen 类负责绘图和更新(游戏逻辑),我在 Windows 消息循环中调用 Draw 和 Update 方法。

谢谢

【问题讨论】:

    标签: c++ directx direct3d directinput


    【解决方案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,这样即使没有要处理的消息,您也可以定期唤醒,但在有消息时立即唤醒。

    【讨论】:

    【解决方案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%。

        使用睡眠功能使程序进入睡眠状态,直到您想轮询直接输入的键。

        因此,如果您正在执行从用户那里收集密钥的简单普通任务,如您所见,直接输入只会浪费编程时间。

        【讨论】:

          猜你喜欢
          • 2012-02-15
          • 2021-02-03
          • 2020-02-17
          • 1970-01-01
          • 2018-03-22
          • 2014-02-13
          • 2011-08-29
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多