Question regarding PeekMessage()

Hello all,

I was reading through some code accompanying a book recently and came upon a use of PeekMessage() that somewhat confuses me. Hopefully someone can help in clarifying this.

The code is from a small DirectX sample that accompanies Frank Luna's book on DirectX 10 ("Introduction to 3D Game Programming with DirectX 10"). The application uses a class called D3DApp to represent it, whose member is a run() function which is the focus of this question. The relevant code goes like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
//in D3DApp.h

class D3DApp
{
public:
	int run();
	void updateScene();
	void drawScene();
	
protected:
	bool mAppPaused; //signifies if App is currently paused
	
	//...
};

//----------------------------

//in D3DApp.cpp

int D3DApp::run()
{
   MSG msg = {0};

   while(msg.message != WM_QUIT)
   {
      // If there are Window messages then process them.
      if(PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
      {
            TranslateMessage( &msg );
            DispatchMessage( &msg );
      }
      // Otherwise, do animation/game stuff.
      else
        {   
         if( !mAppPaused )
            updateScene();   
         else
            Sleep(50);

         drawScene();
        }
    }
   return (int)msg.wParam;
}

void D3DApp::updateScene()
{
	if(GetAsyncKeyState('W') & 0x8000)	
	{
		//move forward
	}
	if(GetAsyncKeyState('A') & 0x8000)	
	{
		//move left
	}
	if(GetAsyncKeyState('S') & 0x8000)	
	{
		//move back
	}
	if(GetAsyncKeyState('D') & 0x8000)	
	{
		//move right
	}
}


(in case anyone wants to see the complete code, it can be found at: http://www.d3dcoder.net/d3d10.htm)

So, in line 27, if(PeekMessage()) is used, which is followed by an else clause in line 33. The whole code for updating the scene and redrawing it is placed in the else block of code. This implies that the scene updates only if there are no messages in the message queue (i.e. PeekMessage() returns false).

What confuses me is the use of the "if-else" (in line 27 and 33). I would expect that something like this would be used in this case (note the lack of "else" in line 12):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
int D3DApp::run()
{
   MSG msg = {0};

   while(msg.message != WM_QUIT)
   {
      if(PeekMessage( &msg, 0, 0, 0, PM_REMOVE ))
      {
            TranslateMessage( &msg );
            DispatchMessage( &msg );
      }
                                      // <---- no "else" used
         if( !mAppPaused )
            updateScene();   
         else
            Sleep(50);

         drawScene(); 
    }
   return (int)msg.wParam;
}


So, since I'm using the code provided in the sample, if I were to press and hold a key, say "W", I would expect that this generates WM_KEYDOWN messages that do not allow the message queue to remain empty (since I am holding the key down). So, I would suppose that the use of "if-else" in this way prevents the scene from updating.

However, upon compiling and running the sample, if I press and hold "W", the scene updates fine, and I get a continuous forward movement. (This is certainly the desired behavior for the program -- we definitely want the scene to update as we press "W", even if it is held down! The question is -- why does it update since a key is held down?)

So -- what am I missing here? Why is the scene updating even though I hold the key down continuously? This would imply that there are iterations of the loop where the message queue is actually empty, and yet I would expect it to not be so since I am holding down a key continuously.

Any feedback would be greatly appreciated! Thank you very much in advance.

Ogoyant
Last edited on
Hmm I haven't done this in like 10 years, but if I recall correctly WM_KEYDOWN is only sent once, then WM_KEYUP is sent when you release the key. So there is not 1 message per frame, but 1 message per KEY press.

In theory you could delay the scene update if you pressed something like 1,000 keys/second :P

Thank you for your reply Zaita, I appreciate it.

Yes, that is a very good point, thank you -- also, refering to MSDN I read that:
Because of the autorepeat feature, more than one WM_KEYDOWN message may be posted before a WM_KEYUP message is posted. The previous key state (bit 30) can be used to determine whether the WM_KEYDOWN message indicates the first down transition or a repeated down transition.


However, the structure of the run() function would seem to restrict scene updates for the given iteration, so long as any messages are present in the queue. I went ahead and added a counter that increments with every call to the WindowProc and outputs the number of calls per second to screen, along with the FPS for the app. As you can see from the run() function, the application does not have a frame-limiter turned on, so every iteration through the loop will update and draw the scene provided no messages are found in the queue.

I'm getting about 170 FPS on my machine, and a reading of ~60 messages per second when pressing and holding a directional key. Moving the mouse around can get the messages up to around 270, and no keyboard presses while the mouse is over the window's client area returns me a constant result of 2. If I remove the mouse from over the window, I get 0 messages. I don't get any noticeable difference to my FPS irrespective of these messages increase or decrease.

What is also interesting to me is that if I remove the else clause from run(), my framerate does not have any considerable difference. It remains around 170 FPS.

From these observations it seems that the rate of generation and handling of the messages is such that it allows the framerate to not get affected, and the application loop to have iterations where the message queue is empty.
Last edited on
No problems :) As I said it has been many many years since I was working on my own 3D engine vs downloading and using a pre-built one (e.g ogre3d)
Topic archived. No new replies allowed.