简体   繁体   English

Win32中的PollEvent()

[英]PollEvent() in Win32

I'm trying to mimic SFML's PollEvent(Event &event) function in Windows. 我正在尝试模仿Windows中SFML的PollEvent(Event &event)函数。 It seems far more complicated that I imagined. 似乎比我想象的要复杂得多。 Note that I already encapsulated the window procedure function in my class. 请注意,我已经将窗口过程函数封装在类中。

There could be many "window events" in my program - WindowMoved , WindowResized etc. 我的程序中可能有很多“窗口事件” WindowMovedWindowResized等。

My first attempt was to have a private data member in the class, defined as WindowEvent *_lastWindowEvent . 我的第一次尝试是在类中有一个私有数据成员,定义为WindowEvent *_lastWindowEvent This variable will be set if PeekMessage() returns a non-zero value, just before DispatchMessage() is called. 如果在调用DispatchMessage()之前PeekMessage()返回非零值,则将设置此变量。 Then, winProc() will edit _lastWindowEvent , depending on the message it will receive. 然后, winProc()将根据收到的消息编辑_lastWindowEvent The drawback here is that I noticed that winProc() may be called with a MSG parameter regardless of DispatchMessage() , like with the WM_SETCURSOR message. 此处的缺点是,我注意到无论与DispatchMessage()一样,均可使用MSG参数调用winProc() DispatchMessage() ,就像WM_SETCURSOR消息一样。

Then I thought about having instead a std::queue<WindowEvent> in my class, when winProc() continuously pushes WindowEvent s to it. 然后,我想到了当winProc()不断将WindowEvent推入类时,在我的类中添加了std::queue<WindowEvent> The problem here is that sometimes the window procedure function keeps getting messages and won't return. 这里的问题是,有时窗口过程函数会不断获取消息,并且不会返回。 This happens when I drag-move the window (then the WM_MOVING message is continuously called, along with other messages). 当我拖动窗口时会发生这种情况(然后连续调用WM_MOVING消息以及其他消息)。 The code after DispatchMessage() will not run until I release my mouse. 在释放鼠标之前, DispatchMessage()之后的代码将无法运行。 This also happens when resizing the window. 调整窗口大小时也会发生这种情况。

Did I grasp anything wrong? 我有什么错吗? How do you think such PollEvent function can be implemented? 您如何看待这样的PollEvent函数?

Given that PollEvent is primarily for a game loop style design, you can probably poll for what you need while simultaneously servicing the Windows event loop: 鉴于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;

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM