The action map is a DIACTIONFORMAT structure containing information about application actions and their mapping to virtual controls or device objects. The structure is passed back and forth between the application and DirectInput to establish the final mapping. This section explains how to initialize the map.
The first step in implementing DirectInput action mapping is to determine what input-driven actions in your application need to be mapped to device objects. For actions that can be performed either by an axis or by a button, you must define separate actions for both input types. It is recommended that you define button actions for all important functions, in case the device does not have the appropriate axes.
The following sample enumeration of action values might be defined by a car-racing game. Axis actions begin with "eA" and button actions with "eB".
enum eGameActions { eA_STEER, // Steering eB_STEER_LEFT, // Steer left eB_STEER_RIGHT, // Steer right eA_ACCELERATE, // Change speed eB_ACCELERATE, // Speed up eB_DECELERATE, // Slow down eA_BRAKE, // Brake eB_BRAKE, // Brake eB_UPSHIFT, // Shift to higher gear eB_DOWNSHIFT, // Shift to lower gear eB_CYCLEVIEW, // Cycle to next view eB_COURSEVIEW, // Toggle course view eB_DRIVERVIEW, // View from driver's seat eB_BRAKEBIAS, // Brake bias eA_VOLUME, // Sound volume eB_MUTE // Toggle sound }; #define NUM_MY_ACTIONS 16
In the example, actions are defined as enumerated values. However, they could be other 32-bit data types, such as pointers to functions. When you retrieve device data, you get whatever action value you have defined, and you can handle it in any way you like.
The next step is to decide what genre your application belongs to. A genre defines a set of virtual controls. By selecting the proper genre, you can obtain the best possible fit of virtual controls to application actions. Manufacturers who choose to supply default mappings for their devices must support one or more of the genres defined by DirectInput. See Action Mapping Constants for a list of these genres.
For the game in the example, the obvious choice is the DIVIRTUAL_DRIVING_RACE genre, which contains the following virtual controls.
Priority 1 Controls
DIAXIS_DRIVINGR_STEER
DIAXIS_DRIVINGR_ACCELERATE
DIAXIS_DRIVINGR_BRAKE
DIBUTTON_DRIVINGR_SHIFTUP
DIBUTTON_DRIVINGR_SHIFTDOWN
DIBUTTON_DRIVINGR_VIEW
DIBUTTON_DRIVINGR_MENU
Priority 2 Controls
DIAXIS_DRIVINGR_ACCEL_AND_BRAKE
DIHATSWITCH_DRIVINGR_GLANCE
DIBUTTON_DRIVINGR_ACCELERATE_LINK
DIBUTTON_DRIVINGR_AIDS
DIBUTTON_DRIVINGR_BOOST
DIBUTTON_DRIVINGR_BRAKE
DIBUTTON_DRIVINGR_DASHBOARD
DIBUTTON_DRIVINGR_DEVICE
DIBUTTON_DRIVINGR_GLANCE_LEFT_LINK
DIBUTTON_DRIVINGR_GLANCE_RIGHT_LINK
DIBUTTON_DRIVINGR_MAP
DIBUTTON_DRIVINGR_PAUSE
DIBUTTON_DRIVINGR_PIT
DIBUTTON_DRIVINGR_STEER_LEFT_LINK
DIBUTTON_DRIVINGR_STEER_RIGHT_LINK
There is no difference in functionality between Priority 1 and Priority 2 controls. Priority 1 controls are those most likely to be supported by device manufacturers in their default mappings. However, there is no guarantee that any virtual control will be supported by a device.
The next step in creating the action map is to associate each application action with one or more of the virtual controls defined for the genre. You do this by declaring and initializing an array of DIACTION structures. Each structure in the array specifies the action value, the virtual control to associate with it, and a friendly name that describes the action. Leave other members as zero; they will be filled in later by DirectInput.
You can also use elements of the DIACTION array to map actions to particular keys or buttons on the keyboard or mouse. By doing so, you can take advantage of the simplified input loop for all input, not just that from virtual controls. For example, suppose you map the application-defined action eB_UPSHIFT to both the DIBUTTON_DRIVINGR_SHIFTUP virtual control and to the Page Up key. When retrieving data, you get back eB_UPSHIFT whether the input came from a joystick button or the keyboard.
The following example declares an action map for the car-racing game.
DIACTION rgActions[]= { //Genre-defined virtual axes {eA_STEER, DIAXIS_DRIVINGR_STEER, 0, "Steer", }, {eA_ACCELERATE, DIAXIS_DRIVINGR_ACCELERATE, 0, "Accelerate", }, {eA_BRAKE, DIAXIS_DRIVINGR_BRAKE, 0, "Brake", }, //Genre-defined virtual buttons {eB_UPSHIFT, DIBUTTON_DRIVINGR_SHIFTUP, 0, "Upshift", }, {eB_DOWNSHIFT, DIBUTTON_DRIVINGR_SHIFTDOWN, 0, "DownShift", }, {eB_CYCLEVIEW, DIBUTTON_DRIVINGR_VIEW, 0, "Change View",}, // Actions not defined in the genre that can be assigned to any // button or axis {eA_VOLUME, DIAXIS_ANY_1, 0, "Volume", }, {eB_MUTE, DIBUTTON_ANY(0), 0, "Toggle Sound",}, // Actions not defined in the genre that must be assigned to // particular keys {eB_DRIVERVIEW, DIKEYBOARD_1, 0, "Driver View",}, {eB_COURSEVIEW, DIKEYBOARD_C, 0, "Course View",}, {eB_BRAKEBIAS, DIKEYBOARD_B, 0, "Brake Bias", }, // Actions mapped to keys as well as to virtual controls {eB_UPSHIFT, DIKEYBOARD_PRIOR, 0, "Upshift", }, {eB_DOWNSHIFT, DIKEYBOARD_NEXT, 0, "Downshift", }, {eB_STEER_LEFT, DIKEYBOARD_LEFT, 0, "Steer Left", }, {eB_STEER_RIGHT, DIKEYBOARD_RIGHT, 0, "Steer Right",}, {eB_ACCELERATE, DIKEYBOARD_UP, 0, "Accelerate", }, {eB_DECELERATE, DIKEYBOARD_DOWN, 0, "Decelerate", }, {eB_BRAKE, DIKEYBOARD_END, 0, "Brake", }, // Actions mapped to buttons as well as to virtual controls and keys {eB_UPSHIFT, DIMOUSE_BUTTON0, 0, "Upshift", }, {eB_DOWNSHIFT, DIMOUSE_BUTTON1, 0, "Downshift", }, };
In the example, some actions are mapped to actual keys by using Keyboard Mapping. Similar mappings to the mouse buttons and axes can be made by using Mouse Mapping.
The DIACTION array is contained within a DIACTIONFORMAT structure that also contains information about the genre, the application, and the desired scaling of axis data. Use the same instance of this structure throughout the action mapping process. Some members will not be used immediately, but you can fill in the entire structure before the next step, Finding Matching Devices.