Tricks of the Windows Game Programming Gurus:Advanced Windows Programming

All ITKnowledge Source Code Search Tips Advanced Search |

| Tricks of the Windows Game Programming Gurus by Andre LaMothe Sams, Macmillan Computer Publishing ISBN: 0672313618 Pub Date: 09/27/99

Search this book:

Previous | Table of Contents | Next

Similarly, you might want to detect when a key is released to turn something off. Here’s an example:

    if (KEYUP(VK_ENTER))

       {

       // disengage engines

       } // end if

As an example, I have created a demo that continually prints out the status of the arrow keys in the `WinMain()`. It’s called `DEMO3_12.CPP`, and the executable is `DEMO3_12.EXE`. Here’s the `WinMain()` from the program:

    int WINAPI WinMain(HINSTANCE hinstance,

                HINSTANCE hprevinstance,

                LPSTR lpcmdline,

                   int ncmdshow)

    {

    WNDCLASSEX winclass; // this will hold the class we create

    HWND       hwnd;     // generic window handle

    MSG       msg;      // generic message

    HDC        hdc;      // graphics device context

    // first fill in the window class stucture

    winclass.cbSize       = sizeof(WNDCLASSEX);

    winclass.style        = CS_DBLCLKS | CS_OWNDC |

                            CS_HREDRAW | CS_VREDRAW;

    winclass.lpfnWndProc = WindowProc;

    winclass.cbClsExtra = 0;

    winclass.cbWndExtra = 0;

    winclass.hInstance = hinstance;

    winclass.hIcon     = LoadIcon(NULL, IDI_APPLICATION);

    winclass.hCursor   = LoadCursor(NULL, IDC_ARROW);

    winclass.hbrBackground   = GetStockObject(BLACK_BRUSH);

    winclass.lpszMenuName   = NULL;

    winclass.lpszClassName   = WINDOW_CLASS_NAME;

    winclass.hIconSm    = LoadIcon(NULL, IDI_APPLICATION);

    // save hinstance in global

    hinstance_app = hinstance;

    // register the window class

    if (!RegisterClassEx(&winclass))

        return(0);

    // create the window

    if (!(hwnd = CreateWindowEx(NULL,               // extended style

                   WINDOW_CLASS_NAME,  // class

                   "GetAsyncKeyState() Demo", // title

                   WS_OVERLAPPEDWINDOW | WS_VISIBLE,

                   0,0,  // initial x,y

                   400,300, // initial width, height

                   NULL,  // handle to parent

                   NULL,  // handle to menu

                  hinstance,// instance of this application

                   NULL))) // extra creation parms

    return(0);

    // save main window handle

    main_window_handle = hwnd;

    // enter main event loop, but this time we use PeekMessage()

    // instead of GetMessage() to retrieve messages

    while(TRUE)

        {

        // test if there is a message in queue, if so get it

        if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))

           {

           // test if this is a quit

           if (msg.message == WM_QUIT)

               break;

           // translate any accelerator keys

           TranslateMessage(&msg);

           // send the message to the window proc

           DispatchMessage(&msg);

           } // end if

           // main game processing goes here

           // get a graphics context

           hdc = GetDC(hwnd);

           // set the foreground color to green

           SetTextColor(hdc, RGB(0,255,0));

           // set the background color to black

           SetBkColor(hdc, RGB(0,0,0));

           // set the transparency mode to OPAQUE

           SetBkMode(hdc, OPAQUE);

           // print out the state of each arrow key

           sprintf(buffer,"Up Arrow: = %d ",KEYDOWN(VK_UP));

           TextOut(hdc, 0,0, buffer, strlen(buffer));

           sprintf(buffer,"Down Arrow: = %d ",KEYDOWN(VK_DOWN));

           TextOut(hdc, 0,16, buffer, strlen(buffer));

           sprintf(buffer,"Right Arrow: = %d ",KEYDOWN(VK_RIGHT));

           TextOut(hdc, 0,32, buffer, strlen(buffer));

           sprintf(buffer,"Left Arrow: = %d ",KEYDOWN(VK_LEFT));

           TextOut(hdc, 0,48, buffer, strlen(buffer));

           // release the dc back

           ReleaseDC(hwnd, hdc);

        } // end while

    // return to Windows like this

    return(msg.wParam);

    } // end WinMain

Also, if you review the entire source on the CD-ROM, you’ll notice that there aren’t handlers for `WM_CHAR` or `WM_KEYDOWN` in the message handler for the window. The fewer messages that you have to handle in the `WinProc()`, the better! In addition, this is the first time you have seen action taking place in the `WinMain()`, which is the section that does all game processing. Notice that there isn’t any timing delay or synchronization, so the redrawing of the information is free-running (in other words, working as fast as possible). In Chapter 4, “Windows GDI, Controls, and Last-Minute Gift Ideas,” you’ll learn about timing issues, how to keep processes locked to a certain frame rate, and so forth. But for now, let’s move on to the mouse.

#### Squeezing the Mouse

The mouse is probably the most innovative computer input device ever created. You point and click, and the mouse pad is physically mapped to the screen surface—that’s innovation! Anyway, as you guessed, Windows has a truckload of messages for the mouse, but we’re going to look at only two classes of messages: `WM_MOUSEMOVE` and `WM_*BUTTON*`.

Let’s start with the `WM_MOUSEMOVE` message. The first thing to remember about the mouse is that its position is relative to the client area of the window that it’s in. Referring to Figure 3.22, the mouse sends coordinates relative to the upper-left corner of your window, which is 0,0.

Figure 3.22 The details of mouse movement.

Other than that, the `WM_MOUSEMOVE` message is fairly straightforward.

Message: `WM_MOUSEMOVE`

Parameterization:

    int mouse_x = (int)LOWORD(lParam);

    int mouse_y = (int)HIWORD(lParam);

    int buttons = (int)wParam;

Basically, the position is encoded as 16-bit entries in the `lparam`, and the buttons are encoded in the `wparam`, as shown in Table 3.9.

Table 3.9 Button Bit Encoding for `WM_MOUSEMOVE`

Value | Description
--- | ---

`MK_LBUTTON` | Set if the left mouse button is down.
`MK_MBUTTON` | Set if the middle mouse button is down.
`MK_RBUTTON` | Set if the right mouse button is down.
`MK_CONTROL` | Set if the Ctrl key is down.
`MK_SHIFT` | Set if the Shift key is down.

So all you have to do is logically `AND` one of the bit codes with the button state and you can detect which mouse buttons are pressed. Here’s an example of tracking the x,y position of the mouse along with the left and right buttons:

    case WM_MOUSEMOVE:

    {

    // get the position of the mouse

    int mouse_x = (int)LOWORD(lParam);

    int mouse_y = (int)HIWORD(lParam);

    // get the button state

    int buttons = (int)wParam;

    // test if left button is down

    if (buttons & MK_LBUTTON)

       {

       // do something

       } // end if

    // test if right button is down

    if (buttons & MK_RBUTTON)

       {

       // do something

       } // end if

    } break;

Previous | Table of Contents | Next

Copyright © Macmillan Computer Publishing, Inc.

Products | Contact Us | About Us | Privacy | Ad Info | Home
Use of this site is subject to certain Terms & Conditions, Copyright © 1996-2000 EarthWeb Inc. All rights reserved. Reproduction in whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Read EarthWeb's privacy statement.