The "Genre and Control definations" documents lists a number of common game genres and primary actions for each genre. An action expresses what application behavior should result from the user's operation of the control.
This example illustrates how a car racing game would use the Dinput mapper
to configure its controls.
The enumerated array eGameActions
supplies the codes that Dinput
uses to communicate the state of controllers.
An application should enumerate all the actions
that it plans to expose to users.
Axis and hatswitch actions should have button or key equivalents,
to allow users to configure those actions on less capable devices.
enum eGameActions = { eA_STEER, /* Steering */ eB_STEER_LEFT, /* Use button to steer to the left */ eB_STEER_RIGHT, /* Use button to steer to the right */ eA_ACCELERATE, /* Accelerate */ eB_ACCELERATE, /* Use button to accelerate */ eB_DEACCELERATE,/* Use button to deaccelerate */ eA_BRAKE, /* Brake */ eB_UPSHIFT, /* Shift to higher gear */ eB_DOWNSHIFT, /* Shift to lower gear */ eB_CYCLEVIEW, /* Cycle to next view */ eB_CONFIGCAR, /* Configure vehicle */ eB_COURSEVIEW, /* Toggle course view */ eB_DRIVERVIEW, /* View from Drivers seat */ eA_VOLUME, /* CD Volume */ eB_BRAKEBIAS, /* Brake Bias */ };
The rgActions
array is used to bind game action codes to virtual device controls.
A game should use predefined action codes, in this case DICARCONTROLLER_*
, to refer to
controls on a virtual car controller. Dinput will examine all connected
devices and enumurate devices suitable for the maping.
The rgActions
should only refer to a single
virtual controller genre and keyboard and mouse.
DIACTIONS rgActions[]= { // Genre Defined controls /************* ****************** **************** Game Action Virtual Controller User Readable Code Action Code Label For Action ************** ****************** ****************/ //Genre defined axes {eA_STEER, DIDEVTYPE_CARCONTROLLER, ABAXIS_STEER, "Steer", 0x0}, {eA_ACCELERATE, DIDEVTYPE_CARCONTROLLER, ABAXIS_ACCEL, "Accelerate", 0x0}, {eA_BRAKE, DIDEVTYPE_CARCONTROLLER, ABAXIS_BRAKE, "Brake", 0x0}, // addition axes not defined as part of the genre {eA_VOLUME, DIDEVTYPE_CARCONTROLLER, ABAXIS_ANY, "CD Volume", 0x0}, // ..more game specific actions //Genre defined buttons {eB_UPSHIFT, DIDEVTYPE_CARCONTROLLER, BUTTON_UPSHIFT, "Upshift", 0x0}, {eB_DOWNSHIFT, DIDEVTYPE_CARCONTROLLER, BUTTON_DWNSHIFT, "DownShift", 0x0}, {eB_CYCLEVIEW, DIDEVTYPE_CARCONTROLLER, BUTTON_VIEWS, "Change View", 0x0}, {eB_CONFIGCAR, DIDEVTYPE_CARCONTROLLER, BUTTON_CONFIGURECAR,"Configure", 0x0}, // Additional actions not defined in the car controller genre // Listed in order of importance. {eB_DRIVERVIEW, DIDEVTYPE_KEYBOARD, DIK_1, "Driver View", 0x0}, {eB_COURSEVIEW, DIDEVTYPE_KEYBOARD, DIK_C, "Course View", 0x0}, {eB_BRAKEBIAS, DIDEVTYPE_KEYBOARD, DIK_B, "Brake Bias", 0x0}, // ... more game specific actions. // Equivalent mappings for keyboard {eB_STEER_L, DIDEVTYPE_KEYBOARD, DIK_LEFT, "Steer Left", 0x0}, {eB_STEER_R, DIDEVTYPE_KEYBOARD, DIK_RIGHT, "Steer Right", 0x0}, {eB_ACCEL_MORE, DIDEVTYPE_KEYBOARD, DIK_UP, "Accelerate", 0x0}, {eB_ACCEL_LESS, DIDEVTYPE_KEYBOARD, DIK_DOWN, "DeAccelerate", 0x0}, // ... additional mappings for keyboard // Equivalent mappings for mouse. {eB_UPSHIFT, DIDEVTYPE_MOUSE, BUTTON_1, "UpShift", 0x0}, {eB_DOWNSHIFT, DIDEVTYPE_MOUSE, BUTTON_2, "DownShift", 0x0}, {eB_CYCLEVIEW, DIDEVTYPE_MOUSE, BUTTON_3, "Cycle View", 0x0}, // ... additional mappings for mouse };
The last few elements of the rgActions
array provide
specific equivalents for controls on keyboard and mice.
The controls on these devices are fairly standard, so there is no need to
provide indirections. The predefined semantic DI_EQUIV
allows the
application to specify equivalent mappings for a control. This flag allows DINPUT
to distuingish between a primary control and a equivalent control. Equivalent controls
only avaliable on the keyboard and mice.
Including these controls in one rgSemantic
makes
the application code simpler. The input processing code of the application
can loop through active input devices and processes data from
{eAch device in a similar manner.
Now that the semantic mappings have been defined, the application can use the
IDirectInput8::EnumDevicesByActions
method in order to enumerate
devices that are suitable for the virtual car controller.
InitializeInput() { IDirectInput* pDI; hr =pDI->EnumDevicesByActions( pDI, // IDirectInput interface &GUID_Application, // Unique GUID for {eAch application rgActions, // Action array TEXT("BillG"), // UserName, 0x0},=>CurrentUser fnDIEnumDevices, // Device Enumeration function NULL, // User variable 0x0 // Enumeration flags ); if(FAILED(hr) { // No device suitable for car controller genre goto panic; } pDi->Rel{eAse(); }
The number of complete devices determines how Dinput configures partial devices. {eAch application is required to provide a GUID that uniquely identifies it. Dinput uses this GUID to keep track of user specified configuration, or to enable enhanced configuration information provided by the hardware vendor that is specific to the application.
BOOL fnDIEnumDevices( IDirectInputDevice8* pDiDev, UINT nID, LPCDIDEVICEINSTANCE lpDiDI, PVOID pv ) { // Display the device mapping // If a user changes the mapping, // the application will need to renogotiate the mapping. hr = pDiDev->DisplayDeviceConfiguration(); if( hr = DIERR_CONFIGCHANGE ) { // User has changed the device configuration, redo the mapping g_bRedoConfig = TRUE; return DIENUM_STOP; }else { // If you decide to keep the device, you need to AddRef pDiDev->AddRef(); g_pDIDevice[nID] = pDiDev; // Stash away a copy of the interface pointer } return DIENUM_CONTINUE; // Look for other devices }
If the user changes the device configuration, this function will return an error code of DIERR_CONFIGCHANGE. This is your cue to renegotiate the mapping.