MULTIMEDIA

Programming with DirectX : Game Input - Win32 Input

9/19/2012 12:56:51 AM
On the PC, numerous devices can be used for input in applications. The most common types of input on PCs are the keyboard and mouse because they are standard when buying or building a PC. When developing games for the PC, developers often focus on these two controller types, while additional controllers such as game pads, steering wheels, and so on are often optional means of input that the users can use if they own and connect such a device to their machines. 

There are three main ways to detect input in a Win32 application. You can use the message pump of the application, you can obtain the state of the device using various Win32 functions, or you can use an API such as XInput, DirectInput, and so forth.

DirectInput

DirectInput is an API that is part of the DirectX SDK that is used to detect input from various devices including the mouse, keyboard, game controllers (e.g., steering wheels, game pads, etc.), and force-feedback devices. DirectInput has traditionally been very beneficial to Windows-based game developers. It has the following benefits that should be taken into consideration.

  • DirectInput talks directly with the hardware.

  • Any input device can work with DirectInput without knowledge of the specific device being used.

  • DirectInput allows for a wide range of devices to be used in an application, each with different features.

  • Outside of using the extended features and services of a device (such as force-feedback), it is fairly simple to use the API to detect input from devices, although the process is more involved than it would be for the XInput API.

One of the most important features of a game’s input system is speed. DirectInput allows developers to talk directly to the hardware, which allows for fast input-state acquiring. Whenever developers make a game, input, although seemingly minor to the inexperienced, is extremely important to get right. Unresponsive input can really hurt player’s experience of a game. Speed is one of the most critical aspects of many different parts of a game, including input.

The major benefit of using DirectInput, aside from its speed, is that DirectInput is an API that allows developers to take advantage of an input device’s extended features and services. Many hardware companies make different devices, and some of these devices have features that many other devices of the same type do not. By following the standard, DirectInput can use devices released on the market without any change to the API. In other words, devices released next year will still work with DirectInput if they follow the standard set forth.

The biggest problem with DirectInput is the difficulty accessing these extended features and services. This includes force-feedback, additional buttons (e.g., a five-button mouse), additional keys, and anything added to the device that is not standard among all devices of the same type (e.g., displays on a keyboard). If you are using DirectInput to detect input from a keyboard and mouse without any additions of a specific device, then there is no benefit because, you can directly obtain the state of a keyboard and mouse device using two Win32 functions for both the keyboard and mouse. This is a long way from all of the setup necessary for DirectInput to do the same thing, and since speed in detecting input exists in both cases, using DirectInput for standard, everyday keyboards and mice has no benefit.

Also, DirectInput has not been updated since DirectX 8.0. It might prove beneficial to use DirectInput to access the features of a device that you cannot access or cannot easily access otherwise, but for everything else it would be beneficial to use the input API. The fact that there is no benefit to using DirectInput in this case is even stated in the DirectX SDK in the DirectInput Introduction section (“The Power of DirectInput”). This fact most likely is one contributing factor to the API’s deprecation.

Windows Message Pump

In Win32 applications, the programmer can use the message pump to obtain messages from the window or from the Windows operating system. These messages include input events such as button presses on a keyboard, button clicks on a mouse, and so forth.

Win32 applications have a feature known as the application loop. This loop runs endlessly until some condition is met to cause the loop to break and the application to quit. What this condition is depends on the specific application and the programmers who have developed it. This condition could be as simple as the user pressing the Esc key, clicking a menu item such as File or Exit, clicking on the Close button, and so on.

In the application loop, as you should already know, a callback procedure is called every time an event is passed to the application’s message pump. The callback is a function that usually executes specific code depending on the event that is passed to it, and it is only called by the application, not by the user.


LRESULT CALLBACK WndProc(HWND hwnd, UINT m, WPARAM wp, LPARAM lp)
{
    // Window width and height.
    int width, height;

    switch(m)
    {
        case WM_CLOSE:
        case WM_DESTROY:
            PostQuitMessage(0);
            return 0;
            break;

        case WM_SIZE:
            height = HIWORD(lp);
            width = LOWORD(lp);
            if(height == 0)
                height = 1;

            ResizeD3D10Window(width, height);
            return 0;
            break;

        case WM_KEYDOWN:
            switch(wp)
            {

               case VK_ESCAPE:
                   PostQuitMessage(0);
                   break;

               default:
                   break;
            }
            break;

        default:
            break;
   }

   // Pass remaining messages to default handler.
   return (DefWindowProc(hwnd, m, wp, lp));
}

					  

The events checked for are the close (WM_CLOSE), destroy (WM_DESTROY), resize (WM_SIZE), and keyboard button presses (WM_KEYDOWN) events. As far as input is concerned, you can check for keys being pressed by checking if the event is a WM_KEYDOWN (or WM_KEYUP for released buttons) event. The WPARAM parameter for the callback procedure stores the value of the event, so for button presses you can check this variable for specific key presses and respond to them accordingly. In the demos the callback procedure checks for the Esc key (VK_ESCAPE), and when this key is pressed, the demos quit their execution.

There are 256 keys on the standard keyboard, and a list of all of the virtual key codes for each button can be found in the MSDN documentation at http://msdn.microsoft.com/en-us/default.aspx. The constants are also defined in windows.h.

Events are passed by the operating system to the application. This is a problem in video games because the time it takes for the OS to notify the application of an event can have a serious impact on input detection and response time. In addition, there is no guarantee of how long it will take the OS to notify the application of an event, so input might not be as fast as real-time applications require. Therefore, it is not recommended that you use the callback procedure for input in your video game applications.

Obtaining Key States in Win32

You can obtain the states of buttons and keys on the keyboard and mouse by using various Win32 functions that will be discussed briefly in this section. You can use DirectInput, but this requires more work to set up, which might not be necessary if you just want standard button and key presses.

The first function we will examine is GetAsyncKeyState(). This function takes as a parameter the virtual key code of the keyboard key or mouse button that you want to test for being pressed. This function tests if the key or button is down at the time the function was called and tests if the key was pressed during a previous call to the function. The value returned by this function is a short integer. If the most significant bit is set, then the key is down; if the least significant bit is set, then the key is up. The function prototype for the GetAsyncKeyState() function is as follows.

SHORT GetAsyncKeyState(int vKey);

An example of testing if the up arrow key is pressed by testing the most significant bit is as follows.

if(GetAsyncKeyState(VK_UP) & 0×80) /*  */

An alternative to the GetAsyncKeyState() function is the GetKeyState() function, which does the same thing, with the exception that the GetKeyState() function returns the key or button information and status that does not reflect the interrupt-level state associated with the hardware.

Another function that can be used to get the state of keyboard keys is the GetKeyboardState() function. This function takes an address as a parameter to a 256-element array that will store the state of all keyboard keys. If the function succeeds in the gathering this keyboard information, the GetKeyboardState() function returns true; if not, it returns false. The function prototype for this function is as follows.

BOOL GetKeyboardState(PBYTE lpKeyState);

For the mouse, it is possible to obtain the mouse’s position by calling the GetCursorPos() function, which takes as a parameter the address to the POINT object that will store the X and Y position of the cursor and returns true or false for whether or not the function succeeded. The function prototype for the GetCursorPos() function is as follows.

BOOL GetCursorPos(LPPOINT lpPoint);

The GetKeyState() and GetAsyncKeyState() functions can be used to return the key state of keyboard keys and mouse buttons.

Other  
  •  Adobe Illustrator CS5 : Proofing and Printing Documents - Setting Advanced Options, Setting Color Management Options
  •  Adobe Illustrator CS5 : Setting Graphics Options, Previewing Color Separations, Setting Output Options
  •  Adobe Illustrator CS5 : Setting General Print Options, Setting Marks and Bleed Options
  •  AC-1 Ammoclip for Xbox 360 - Keep Shooting!
  •  Buyer's Guide: 3D Monitors (Part 3) - BenQ XL2420T, Samsung SyncMaster S23A750D, Asus VG278H
  •  Buyer's Guide: 3D Monitors (Part 2) - ViewSonic V3D231, LG DM2350D, HP 2311GT
  •  Buyer's Guide: 3D Monitors (Part 1) - LG D2342P, AOC e2352PHz
  •  Aperion Audio Zona Wireless Speaker System
  •  TX-2 Throat Mic - Covert Ops
  •  Philips Sound Tower DCM5090 - Elegant and Versatile
  •  EX-05 Multi-Format Wireless Headset - In The Army
  •  Gioteck HF-2 Controller - Different Strokes
  •  VX-1 Wireless Controller for PS3 – Big Improvement
  •  Sennheiser HD700 - Welcome To Audio Heaven
  •  Adobe Photoshop CS5 : Working with Automate Commands - Merging Images to HDR
  •  Adobe Photoshop CS5 : Working with Automate Commands - Using Photomerge
  •  Vive La Resolution
  •  Belkin ScreenCast AV4
  •  Has Google Sold SketchUp Down The River?
  •  Hot 5 Products To Make Your Life Interesting
  •  
    Top 10
    Nikon 1 J2 With Stylish Design And Dependable Image And Video Quality
    Canon Powershot D20 - Super-Durable Waterproof Camera
    Fujifilm Finepix F800EXR – Another Excellent EXR
    Sony NEX-6 – The Best Compact Camera
    Teufel Cubycon 2 – An Excellent All-In-One For Films
    Dell S2740L - A Beautifully Crafted 27-inch IPS Monitor
    Philips 55PFL6007T With Fantastic Picture Quality
    Philips Gioco 278G4 – An Excellent 27-inch Screen
    Sony VPL-HW50ES – Sony’s Best Home Cinema Projector
    Windows Vista : Installing and Running Applications - Launching Applications
    Most View
    Bamboo Splash - Powerful Specs And Friendly Interface
    Powered By Windows (Part 2) - Toshiba Satellite U840 Series, Philips E248C3 MODA Lightframe Monitor & HP Envy Spectre 14
    MSI X79A-GD65 8D - Power without the Cost
    Canon EOS M With Wonderful Touchscreen Interface (Part 1)
    Windows Server 2003 : Building an Active Directory Structure (part 1) - The First Domain
    Personalize Your iPhone Case
    Speed ​​up browsing with a faster DNS
    Using and Configuring Public Folder Sharing
    Extending the Real-Time Communications Functionality of Exchange Server 2007 : Installing OCS 2007 (part 1)
    Google, privacy & you (Part 1)
    iPhone Application Development : Making Multivalue Choices with Pickers - Understanding Pickers
    Microsoft Surface With Windows RT - Truly A Unique Tablet
    Network Configuration & Troubleshooting (Part 1)
    Panasonic Lumix GH3 – The Fastest Touchscreen-Camera (Part 2)
    Programming Microsoft SQL Server 2005 : FOR XML Commands (part 3) - OPENXML Enhancements in SQL Server 2005
    Exchange Server 2010 : Track Exchange Performance (part 2) - Test the Performance Limitations in a Lab
    Extra Network Hardware Round-Up (Part 2) - NAS Drives, Media Center Extenders & Games Consoles
    Windows Server 2003 : Planning a Host Name Resolution Strategy - Understanding Name Resolution Requirements
    Google’s Data Liberation Front (Part 2)
    Datacolor SpyderLensCal (Part 1)