Pumping messages while waiting for a period of time!

Advanced game related topics
User avatar
Mijikai
Addict
Addict
Posts: 1360
Joined: Sun Sep 11, 2016 2:17 pm

Pumping messages while waiting for a period of time!

Post by Mijikai »

I found a post by Raymond Chen describing how to pump messages while waiting for a period of time.
This might be relevant for making a better timing system for games.

I translated the code in the article to PureBasic:

Code: Select all

EnableExplicit

;Pumping messages while waiting for a period of time!

;Based on the code shown by Raymond Chen: https://devblogs.microsoft.com/oldnewthing/20060126-00/?p=32513

;Article:

;We can use the MsgWaitForMultipleObjects function (or its superset MsgWaitForMultipleObjectsEx) 
;to carry out a non-polling “sleep while processing messages”.

;This function pumps messages for up to dwTimeout milliseconds.
;The kernel of the idea is merely to use the MsgWaitForMultipleObjects/Ex function as a surrogate for WaitMessageTimeout,
;pumping messages until the cumulative timeout has been reached. There are a lot of small details to pay heed to, however.
;I’ve linked them to earlier postings that discuss the specific issues, if you need a refresher. 
;The CallMsgFilter you might find gratuitous, but you’ll change your mind when you realize that users might press a keyboard accelerator while you’re sleeping,
;and you presumably want it to go through somebody’s TranslateAccelerator.
;The message filter lets you hook into the modal loop and do your accelerator translation. 
;Extending this function to “wait on a set of handles up to a specified amount of time, while pumping messages”
;is left as an exercise. (You can do it without changing very many lines of code.)

;Code:

; #define MSGF_SLEEPMSG 0x5300
; BOOL SleepMsg(DWORD dwTimeout)
; {
;  DWORD dwStart = GetTickCount();
;  DWORD dwElapsed;
;  while ((dwElapsed = GetTickCount() - dwStart) < dwTimeout) {
;   DWORD dwStatus = MsgWaitForMultipleObjectsEx(0, NULL,
;                     dwTimeout - dwElapsed, QS_ALLINPUT,
;                     MWMO_WAITANY | MWMO_INPUTAVAILABLE);
;   if (dwStatus == WAIT_OBJECT_0) {
;    MSG msg;
;    while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
;     if (msg.message == WM_QUIT) {
;      PostQuitMessage((int)msg.wParam);
;      return FALSE; // abandoned due to WM_QUIT
;     }
;     if (!CallMsgFilter(&msg, MSGF_SLEEPMSG)) {
;      TranslateMessage(&msg);
;      DispatchMessage(&msg);
;     }
;    }
;   }
;  }
;  return TRUE; // timed out
; }

;Code translated to PureBasic (PB 5.73 LTS x64)

;Note: 
;- PollEvents() is untested - so if there is an translation error please let me know.

#MWMO_WAITANY = $0000;<- missing constants for (legacy) APIs...
#MWMO_INPUTAVAILABLE = $0004
#MSGF_SLEEPMSG = $5300

Procedure.b PollEvents(Timeout.i)
  Protected start.i
  Protected elapsed.i
  Static task.MSG
  start = timeGetTime_()
  While elapsed < Timeout
    elapsed = timeGetTime_() - start
    If MsgWaitForMultipleObjectsEx_(#Null,#Null,Timeout - elapsed,#QS_ALLINPUT,#MWMO_WAITANY|#MWMO_INPUTAVAILABLE) = #WAIT_OBJECT_0
      While PeekMessage_(@task,#Null,#Null,#Null,#PM_REMOVE)
        If task\message = #WM_QUIT
          PostQuitMessage_(task\wParam)
          ProcedureReturn #False
        EndIf
        If CallMsgFilter_(@task,#MSGF_SLEEPMSG)
          TranslateMessage_(@task)
          DispatchMessage_(@task)
        EndIf
      Wend
      ProcedureReturn #True
    EndIf
  Wend
  ProcedureReturn #False
EndProcedure
User avatar
Caronte3D
Addict
Addict
Posts: 1027
Joined: Fri Jan 22, 2016 5:33 pm
Location: Some Universe

Re: Pumping messages while waiting for a period of time!

Post by Caronte3D »

A little example would be good to understand the use of this procedure :oops:
BarryG
Addict
Addict
Posts: 3293
Joined: Thu Apr 18, 2019 8:17 am

Re: Pumping messages while waiting for a period of time!

Post by BarryG »

Yeah, I have no idea what "pump messages" means here.
User avatar
darius676
Enthusiast
Enthusiast
Posts: 278
Joined: Thu Jan 31, 2019 12:59 am
Contact:

Re: Pumping messages while waiting for a period of time!

Post by darius676 »

Why not make it simple like this:
Use a timerbase (elapsedmilliseconds()) for the main calculations. If timer is ready, do calculation, if not just update/show actual situation on screen. So the calculation (update) is not Hardware/Performance/Framerate related and faster systems will show the same situation as not so performant setups.
Should be simple and practically.
Post Reply