【问题标题】:PollEvent() in Win32Win32 中的 PollEvent()
【发布时间】:2015-12-29 01:17:57
【问题描述】:

我正在尝试在 Windows 中模仿 SFML 的 PollEvent(Event &event) 函数。它似乎比我想象的要复杂得多。请注意,我已经在我的类中封装了窗口过程函数。

我的程序中可能有很多“窗口事件”——WindowMoved、WindowResized 等。

我的第一次尝试是在类中有一个私有数据成员,定义为WindowEvent *_lastWindowEvent。如果PeekMessage() 在调用DispatchMessage() 之前返回非零值,则将设置此变量。然后,winProc() 将编辑_lastWindowEvent,具体取决于它将收到的消息。 这里的缺点是我注意到winProc() 可以使用MSG 参数调用而不管DispatchMessage(),就像WM_SETCURSOR 消息一样。

然后我想在我的课堂上改用std::queue<WindowEvent>,当winProc()不断向它推送WindowEvents。这里的问题是有时窗口过程函数不断收到消息并且不会返回。当我拖动窗口时会发生这种情况(然后不断调用WM_MOVING 消息以及其他消息)。 DispatchMessage() 之后的代码在我松开鼠标之前不会运行。调整窗口大小时也会发生这种情况。

我有没有搞错什么?您觉得这样的 PollEvent 功能如何实现?

【问题讨论】:

  • Replaying input is not the same as reprocessing it。如果您决定违反合同,您最终会重新发明 Qt 的损坏性。 Qt 被打破,无法重生。你所描述的听起来很像 Trolltech 的,err,Digia 的,等等,Qt 公司(这就是他们本周所说的)的想法。结果证明这是一个可憎的事。
  • @IInspectable - 不确定我刚刚读到什么。你能进一步解释一下吗?
  • 如果您将窗口消息存储在您的私有队列中,然后将它们交给处理,它将以微妙的方式失败。上面的链接解释了为什么输入消息失败。您有一次处理消息的机会(在您的窗口过程中)。不要浪费它。
  • 那么真正将win32封装在一个类中,包括win过程,是不可能的?
  • 完全没有,但您必须满足消息传递系统的要求。您可以将窗口过程作为类成员。但是,根据个人经验,最好将消息循环保持在框架之外。让客户端实现自己的消息循环可能看起来不必要地繁琐且容易出错,但它确实提供了很大的灵活性。如果客户决定调用MsgWaitForMultipleObjects 而不是GetMessage,他们希望框架不会妨碍。

标签: windows winapi sfml


【解决方案1】:

鉴于 PollEvent 主要用于游戏循环样式设计,您可能可以在为 Windows 事件循环提供服务的同时轮询您需要的内容:

class Window
{
    HWND _hwnd;           // Win32 handle to the window
    RECT _lastWindowSize; // last known window size
    POINT _lastMousePos;  // last known mouse position on window
    BYTE _lastKeyboardState[256]; // last known key state

    std::list<Event> _events; // unprocessed events

public:
    bool PollEvent(Event* pEvent);
};


bool Window::PollEvent(Event* pEvent)
{

   // return any previously queued events
   if (_events.size() > 0)
   {
        *pEvent = _events.pop_front();
        return true;
   }

   // process 1 windows event message
   if (PeekMessage(&msg, _hWnd, 0, 0, PM_REMOVE))
   {
       TranslateMessage(&msg);
       DispatchMessage(&msg);

       if (msg.msg == WM_QUIT)
       { 
           *pEvent = EXIT_EVENT; // special handling for WM_QUIT
           return true;
       }
   }

   // -----------------------------------------
   // poll keyboard state
   BYTE kbState[256];
   GetKeyboardState(kbState);
   bool isKeyboardEvent = false;
   if (memcmp(_lastKeyboardState, kbState, 256) != 0)
   {
        // not shown
        // compute diff of kbState and _lastKeyboardState
        // generate a keyboard event and add to the queue

        Event kbevt;
        kbevt.type = KeyEvent;
        kbevt.code = <computed code based on diff above>
        _events.push_back(kbevt);
   }
   memcpy(_lastKeyboardState, kbState, 256);
   // -----------------------------------------

   // -----------------------------------------
   // poll window size changes
   RECT rectWindowSize;
   int width, height, oldwidth, oldheight;
   GetClientRect(&rectWindowSize);
   width = rectWindowSize.right - rectWindowSize.left;
   height = rectWindowSize.bottom - rectWindowSize.top;
   oldwidth = _lastWindowSize.right - _lastWindowSize.left;
   oldheight = _lastWindowSize.bottom - _lastWindowSize.top;
   if ((width != oldwidth) || (height != oldheight))
   {
       Event sizeEvent;
       sizeEvent.type = SizeEvent;
       sizeEvent.width = width;
       sizeEvent.height = height;
       _events.push_back(kbevt);
   }
   _lastWindowSize = rectWindowSize;
   // -----------------------------------------

   // not shown - computing mouse position, joystick position, text stuff


   // if at least one event was queued - return it now
   if (_events.size() > 0)
   {
        *pEvent = _events.pop_front();
        return true;
   }

   return false;

}

【讨论】:

  • 这一切中的窗口过程函数在哪里?
  • @Pilpel - 你知道如何定义基本的 WndProc 函数并将其与 C++ 类相关联吗?如果没有,我可以告诉你如何实现。
  • 这并没有解决我注意到的第二个问题。如果用户拖动并移动窗口,队列将被数千条消息淹没,直到用户松开鼠标按钮
  • @Pilpel - 您的问题一开始就含糊不清,您没有发布任何您尝试过的代码。所以我认为这是您寻求帮助的设计问题。我没有观察到 DispatchMessage 在鼠标按下时阻塞,所以我需要查看一些代码(由您共享)来评估问题。
  • 另外,我从来不明白你所说的“模仿 SFML 的 PollEvent”是什么意思。这是否意味着您没有使用 SFML?或者你正在尝试做类似的事情?或者您正在尝试使用自己的事件循环来扩展 SFML?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多