|
|
<HEAD> <TITLE>DirectInput Input Mapper</TITLE> </HEAD> <BODY BGCOLOR=#FFFFFF TEXT=#000000 LINK=#000000 VLINK=#808080 ALINK=#000000> </BODY>
<H2>DirectInput Input Mapper</H2>
<ADDRESS> Om Sharma<br> Microsoft Corporation<br> 6 June 1999 </ADDRESS>
<h3>Abstract</h3>
<p> 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. </p>
<h3>How games use Actions</h3>
<p> This example illustrates how a car racing game would use the Dinput mapper to configure its controls. The enumerated array <code>eGameActions</code> 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. </p>
<pre>
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 */ }; </pre> <p> The <code>rgActions</code> array is used to bind game action codes to virtual device controls. A game should use predefined action codes, in this case <code>DICARCONTROLLER_*</code>, to refer to controls on a virtual car controller. Dinput will examine all connected devices and enumurate devices suitable for the maping. The <code>rgActions</code> should only refer to a single virtual controller genre and keyboard and mouse. </p> <pre> 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
}; </pre>
</p> The last few elements of the <code>rgActions</code> 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 <code>DI_EQUIV</code> 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. <p> </p> Including these controls in one <code>rgSemantic</code> 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. </p>
<p> Now that the semantic mappings have been defined, the application can use the <code>IDirectInput8::EnumDevicesByActions</code> method in order to enumerate devices that are suitable for the virtual car controller. </p>
<pre> 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(); } </pre> <p> 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.
</p> <pre> 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 }
</pre> <p> 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. </p>
|