Search Tips Advanced Search |
| Delphi Graphics and Game Programming Exposed with DirectX 7.0 by John Ayres Wordware Publishing, Inc. ISBN: 1556226373 Pub Date: 12/01/99
Search this book:
Previous | Table of Contents | Next
#### Mouse Input The other standard input device, the mouse, is probably used in just about every type of game for allowing the user to choose options and to set up game parameters. While it is almost as easy to read mouse data as it is the keyboard, there are certain nuances that must be considered. The mouse returns data for up to three buttons and up to three axes. Since DirectInput works directly with the mouse driver, any control panel settings for the mouse are ignored, such as button swapping. However, the application could check on the status of button swapping by calling GetSystemMetrics(SW_SWAPBUTTON). The axis data returned by the mouse is relative by nature, as the mouse can move infinitely in any direction. These values are arbitrary and not based on screen coordinates, control panel settings, etc. The x-axis and y-axis values returned by the mouse correspond to the horizontal and vertical movements of the physical device; mouse wheel values will be reported as a z-axis. As in the windowed world, mouse travel to the left or away from the user is negative, and right or toward the user is positive. DirectInput allows you to retrieve axis movement, but it does not provide a mouse cursor (under exclusive mode). This must be implemented in the application itself. This is certainly not a difficult task, as you know where to draw the mouse cursor by the x-axis and y-axis values you’ve retrieved (as they pertain to your application). This allows you to implement elaborate animated mouse cursors using techniques as discussed in the chapter on sprites. The animation could even be context sensitive based on the position of the cursor or the current game state. The only thing to keep in mind is that you will want to draw the mouse cursor as the last step of your rendering process so it is not obscured by other graphics.
| Note: Setting a non-exclusive cooperative level will display a mouse cursor, but it will flicker horribly in a page flipping architecture such as that used throughout this book. It is usually best to acquire the mouse exclusively and implement your own mouse cursor drawing functionality.
One drawback to drawing the mouse cursor in this manner is that its responsiveness will be very dependent on the frame rate of the application itself. For example, say the user starts the game on a very slow machine, and it has a frame rate of about five frames per second. If you draw your mouse cursor at the end of the rendering loop, it will be very jerky and unresponsive, and could make leaving the game very difficult indeed. In order to combat this dependence on the game’s overall frame rate, we will be implementing a multithreaded solution for drawing the mouse cursor. This multithreaded architecture will also be useful for detecting available mouse input through event notification. This technique involves the use of Windows event objects as well as a critical section for thread synchronization. This complex architecture will be covered in more detail below. Windows Functions Windows provides developers with the GetCursorPos function, which is very similar to retrieving immediate mouse data for the cursor position using DirectInput. The GetAsyncKeyState function can be used to retrieve the current state of mouse buttons. The GetCursorPos function is defined as:
    function GetCursorPos(

    var lpPoint: TPoint                       // receives coordinates of cursor

    ): BOOL;                                  // returns TRUE or FALSE
This function’s only parameter is a TPoint variable that receives the horizontal and vertical coordinate of the mouse cursor’s current position. For applications that only require a modicum of mouse input, this function may be more than adequate. The following example demonstrates the use of this function. Listing 7-5: Retrieving mouse input through GetCursorPos
    procedure TForm1.Timer1Timer(Sender: TObject);

    var

      CursorPos: TPoint;

    begin

      {retrieve the position of the mouse cursor}

      GetCursorPos(CursorPos);

      {the retrieved position is in screen coordinates, so we must convert them

       to client coordinates}

      CursorPos := ScreenToClient(CursorPos);

      {draw the background into the offscreen buffer, erasing the last frame’}

      Offscreen.Canvas.Draw(0, 0, Background);

      {now, transparently draw our custom mouse cursor into the offscreen buffer.

       note that we’ve moved the hotspot’ so that it will be in the center of the

       cursor}

      BitBlt(Offscreen.Canvas.Handle, CursorPos.X-16, CursorPos.Y-16,

             CursorAND.Width, CursorAND.Height, CursorAND.Canvas.Handle, 0, 0,

             SRCAND);

      BitBlt(Offscreen.Canvas.Handle, CursorPos.X-16, CursorPos.Y-16,

             CursorOR.Width, CursorOR.Height, CursorOR.Canvas.Handle, 0, 0,

             SRCPAINT);

      {finally, draw the new frame of animation onto the screen}

      Canvas.Draw(0, 0, Offscreen);

    end;
One drawback with GetCursorPos is that it reports the position of the mouse in relation to the screen, and thus is an absolute measurement as it reports values in the range of 0, 0 to screen width, screen height. This may be fine for some games, but others may require the infinite resolution and quicker response offered by DirectInput. DirectInput Initialization We must follow most of the steps outlined above to initialize DirectInput to receive mouse data. Since we are dealing with a stream of relative axis values, we will use the buffered method of input data retrieval. Therefore, unlike the keyboard, we must set certain properties of the device to initialize this buffer. Due to our multithreaded architecture, we have a few more tasks to complete, some of which are not directly related to DirectInput.
| Note: Retrieving immediate mouse data is similar to retrieving immediate keyboard data, and will return the cumulative sum of all axes movements since the last call to GetDeviceState.
The first order of business is creating the DirectInput object. We can then immediately create an IDirectInputDevice object for the primary mouse using the GUID_SysMouse value. Since it’s not likely that the mouse will have force feedback capabilities, we’ll skip querying for an IDirectInputDevice2 object. We must then set the data format to c_dfDIMouse, the standard mouse data format. We’ll then set the cooperative level for foreground, exclusive. These steps are illustrated below.
Previous | Table of Contents | Next

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 whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Read EarthWeb's privacy statement.