di-diagnostics.cpp

Go to the documentation of this file.
00001 /*
00002  * di-diagnostics.cpp
00003  *
00004  * Copyright (C) 2010  Thomas A. Vaughan
00005  * All rights reserved.
00006  *
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted provided that the following conditions are met:
00010  *     * Redistributions of source code must retain the above copyright
00011  *       notice, this list of conditions and the following disclaimer.
00012  *     * Redistributions in binary form must reproduce the above copyright
00013  *       notice, this list of conditions and the following disclaimer in the
00014  *       documentation and/or other materials provided with the distribution.
00015  *     * Neither the name of the <organization> nor the
00016  *       names of its contributors may be used to endorse or promote products
00017  *       derived from this software without specific prior written permission.
00018  *
00019  * THIS SOFTWARE IS PROVIDED BY THOMAS A. VAUGHAN ''AS IS'' AND ANY
00020  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00021  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00022  * DISCLAIMED. IN NO EVENT SHALL THOMAS A. VAUGHAN BE LIABLE FOR ANY
00023  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00024  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00025  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00026  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00027  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00028  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00029  *
00030  *
00031  * Helper and diagnostic routines for the Microsoft DirectX DirectInput APIs
00032  */
00033 
00034 // includes --------------------------------------------------------------------
00035 #include "di-diagnostics.h"             // always include our own header first
00036 
00037 #include <iostream>
00038 
00039 
00040 namespace gamepad {
00041 
00042 
00043 struct odf_type_entry_t {
00044         dword_t         type;   // type flag
00045         const char *    name;
00046 };
00047 
00048 #define ODFTYPE( token ) { DIDFT_ ##token , #token },
00049 
00050 static const odf_type_entry_t s_odfTypes[] =
00051 {
00052         ODFTYPE(ABSAXIS)
00053         ODFTYPE(ALIAS)
00054         ODFTYPE(AXIS)
00055         ODFTYPE(BUTTON)
00056         ODFTYPE(COLLECTION)
00057         ODFTYPE(FFACTUATOR)
00058         ODFTYPE(FFEFFECTTRIGGER)
00059         ODFTYPE(NOCOLLECTION)
00060         ODFTYPE(NODATA)
00061         ODFTYPE(OUTPUT)
00062         ODFTYPE(POV)
00063         ODFTYPE(PSHBUTTON)
00064         ODFTYPE(RELAXIS)
00065         ODFTYPE(TGLBUTTON)
00066         ODFTYPE(VENDORDEFINED)
00067 
00068         // must be last!
00069         { 0, NULL }
00070 };
00071 
00072 
00073 struct odf_flag_entry_t {
00074         dword_t         flag;   // flag value
00075         const char *    name;
00076 };
00077 
00078 #define ODFFLAG( token ) { DIDOI_ ##token , #token },
00079 
00080 static const odf_flag_entry_t s_odfFlags[] =
00081 {
00082         ODFFLAG(ASPECTACCEL)
00083         ODFFLAG(ASPECTFORCE)
00084         ODFFLAG(ASPECTPOSITION)
00085         ODFFLAG(ASPECTVELOCITY)
00086 
00087         // must be last!
00088         { 0, NULL }
00089 };
00090 
00091 
00092 struct dc_flag_entry_t {
00093         dword_t         flag;   // flag value
00094         const char *    name;
00095 };
00096 
00097 #define DCFLAG( token ) { DIDC_ ##token , #token },
00098 
00099 static const dc_flag_entry_t s_dcFlags[] = {
00100         DCFLAG(ALIAS)
00101         DCFLAG(ATTACHED)
00102         DCFLAG(DEADBAND)
00103         DCFLAG(EMULATED)
00104         DCFLAG(FORCEFEEDBACK)
00105         DCFLAG(FFFADE)
00106         DCFLAG(FFATTACK)
00107         DCFLAG(HIDDEN)
00108         DCFLAG(PHANTOM)
00109         DCFLAG(POLLEDDATAFORMAT)
00110         DCFLAG(POLLEDDEVICE)
00111         DCFLAG(POSNEGCOEFFICIENTS)
00112         DCFLAG(POSNEGSATURATION)
00113         DCFLAG(SATURATION)
00114         DCFLAG(STARTDELAY)
00115 
00116         // must be last!
00117         { 0, NULL }
00118 };
00119 
00120 
00121 
00122 struct guid_entry_t {
00123         GUID            guid;
00124         const char *    name;
00125         const GUID *    pguid;
00126 };
00127 
00128 #define GUID_ENTRY(g) { GUID_ ## g , "GUID_" #g , &GUID_ ## g },
00129 
00130 static const guid_entry_t s_guids[] = {
00131         GUID_ENTRY(XAxis)
00132         GUID_ENTRY(YAxis)
00133         GUID_ENTRY(ZAxis)
00134         GUID_ENTRY(RxAxis)
00135         GUID_ENTRY(RyAxis)
00136         GUID_ENTRY(RzAxis)
00137         GUID_ENTRY(Slider)
00138         GUID_ENTRY(Button)
00139         GUID_ENTRY(Key)
00140         GUID_ENTRY(POV)
00141         GUID_ENTRY(Unknown)
00142 
00143         // must be last
00144         { GUID_XAxis, NULL, NULL }
00145 };
00146 
00147 
00148 typedef std::vector<DIOBJECTDATAFORMAT> vec_objdf_t;
00149 
00150 
00151 struct enum_objs_context_t {
00152         // constructor, manipulators
00153         enum_objs_context_t(void) throw() { this->clear(); }
00154         void clear(void) throw() {
00155                         objects.clear();
00156                         dc.clear();
00157                 }
00158 
00159         // data fields
00160         vec_objdf_t             objects;        // vector of objects
00161         device_caps_t           dc;             // detected capabilities
00162 };
00163 
00164 
00165 
00166 ////////////////////////////////////////////////////////////////////////////////
00167 //
00168 //      static helper methods
00169 //
00170 ////////////////////////////////////////////////////////////////////////////////
00171 
00172 static const GUID *
00173 getGuidPointer
00174 (
00175 IN const GUID& rg
00176 )
00177 {
00178         for (const guid_entry_t * p = s_guids; p->pguid; ++p) {
00179                 if (p->guid == rg) {
00180                         return p->pguid;
00181                 }
00182         }
00183 
00184         // got here?  Unknown...
00185         std::cerr << "Unrecognized DirectInput object guid: " << rg << "\n";
00186         return NULL;
00187 }
00188 
00189 
00190 
00191 static const char *
00192 getGuidName
00193 (
00194 IN const GUID * pg
00195 )
00196 {
00197         ASSERT(pg, "null");
00198 
00199         for (const guid_entry_t * p = s_guids; p->name; ++p) {
00200                 if (p->guid == *pg) {
00201                         return p->name;
00202                 }
00203         }
00204 
00205         // unknown!
00206         return "<unrecognized>";
00207 }
00208 
00209 
00210 
00211 static void
00212 writeODFType
00213 (
00214 IO std::ostream& stream,
00215 IN dword_t dwType
00216 )
00217 {
00218         for (const odf_type_entry_t * p = s_odfTypes; p->name; ++p) {
00219                 if (dwType & p->type) {
00220                         stream << p->name << " ";
00221                 }
00222         }
00223 }
00224 
00225 
00226 
00227 static void
00228 writeODFFlags
00229 (
00230 IO std::ostream& stream,
00231 IN dword_t dwFlags
00232 )
00233 {
00234         for (const odf_flag_entry_t * p = s_odfFlags; p->name; ++p) {
00235                 if (dwFlags & p->flag) {
00236                         stream << p->name << " ";
00237                 }
00238         }
00239 }
00240 
00241 
00242 
00243 static void
00244 writeDCFlags
00245 (
00246 IO std::ostream& stream,
00247 IN dword_t dwFlags
00248 )
00249 {
00250         for (const dc_flag_entry_t * p = s_dcFlags; p->name; ++p) {
00251                 if (dwFlags & p->flag) {
00252                         stream << p->name << " ";
00253                 }
00254         }
00255 }
00256 
00257 
00258 
00259 static BOOL CALLBACK
00260 objectCallback
00261 (
00262 LPCDIDEVICEOBJECTINSTANCE lpddoi,
00263 LPVOID pvRef
00264 )
00265 {
00266         ASSERT(lpddoi, "null");
00267         enum_objs_context_t * peoc = (enum_objs_context_t *) pvRef;
00268         ASSERT(peoc, "null");
00269 
00270         // do we care about this type?
00271         std::cerr << "Inspecting object: " << lpddoi->tszName << "\n";
00272         std::cerr << "  type: ";
00273         writeODFType(std::cerr, lpddoi->dwType);
00274         std::cerr << "\n";
00275         std::cerr << "  flags: ";
00276         writeODFFlags(std::cerr, lpddoi->dwFlags);
00277         std::cerr << "\n";
00278         std::cerr << "  guid: " << getGuidName(&lpddoi->guidType) << "\n";
00279 
00280         DIOBJECTDATAFORMAT odf;
00281         odf.dwType = lpddoi->dwType;
00282         odf.dwFlags = lpddoi->dwFlags;
00283         if (DIDFT_ABSAXIS & lpddoi->dwType) {
00284                 DPRINTF("Absolute Axis!");
00285                 peoc->dc.nAxes++;
00286         } else if (DIDFT_PSHBUTTON & lpddoi->dwType) {
00287                 DPRINTF("Push button!");
00288                 peoc->dc.nButtons++;
00289         } else if (DIDFT_POV & lpddoi->dwType) {
00290                 DPRINTF("Dpad!");
00291                 peoc->dc.nPOVs++;
00292         } else {
00293                 DPRINTF("unknown type, skipping");
00294                 return DIENUM_CONTINUE;
00295         }
00296 
00297         // update guid
00298         odf.pguid = getGuidPointer(lpddoi->guidType);
00299 
00300         // got here?  Add to collection
00301         peoc->objects.push_back(odf);
00302 
00303         // why did they declare it BOOL then define their own enums?
00304         return DIENUM_CONTINUE;
00305 }
00306 
00307 
00308 
00309 ////////////////////////////////////////////////////////////////////////////////
00310 //
00311 //      public API
00312 //
00313 ////////////////////////////////////////////////////////////////////////////////
00314 
00315 #define DIE_VALUE(token) case token : DPRINTF("  ...%s", #token ); break;
00316 
00317 void
00318 checkDIError
00319 (
00320 IN HRESULT hr
00321 )
00322 {
00323         DPRINTF("Checking DirectInput result code 0x%08x = %ld...", hr, hr);
00324         switch (hr) {
00325         DIE_VALUE(DI_OK)
00326         DIE_VALUE(DIERR_ACQUIRED)
00327         DIE_VALUE(DIERR_DEVICENOTREG)
00328         DIE_VALUE(DIERR_INPUTLOST)
00329         DIE_VALUE(DIERR_INVALIDPARAM)
00330         DIE_VALUE(DIERR_NOINTERFACE)
00331         DIE_VALUE(DIERR_NOTINITIALIZED)
00332         DIE_VALUE(DIERR_OBJECTNOTFOUND)
00333         DIE_VALUE(DIERR_OTHERAPPHASPRIO)
00334         DIE_VALUE(DIERR_OUTOFMEMORY)
00335         DIE_VALUE(DIERR_UNSUPPORTED)
00336         default:
00337                 DPRINTF("  ...not a recognized DirectInput result code!");
00338                 DPRINTF("  Checking basic Windows HRESULT codes...");
00339                 checkHresult(hr);
00340         }
00341 }
00342 
00343 
00344 
00345 void
00346 writeDevInstance
00347 (
00348 IO std::ostream& stream,
00349 IN const DIDEVICEINSTANCEA& di
00350 )
00351 {
00352         ASSERT_THROW(stream.good(), "bad stream?");
00353 
00354         stream << "DirectInput device instance structure:\n";
00355         int type = (di.dwDevType & 0xff);
00356         int subtype = ((di.dwDevType >> 8) & 0xff);
00357         stream << "  struct size: " << di.dwSize << " bytes\n";
00358         stream << "  type: " << type << ", subtype: " << subtype << "\n";
00359         stream << "  guidInstance: " << di.guidInstance << "\n";
00360         stream << "  guidProduct: " << di.guidProduct << "\n";
00361         stream << "  tszInstanceName: " << di.tszInstanceName << "\n";
00362         stream << "  tszFriendlyName: " << di.tszProductName << "\n";
00363         stream << "  guidFFDriver: " << di.guidFFDriver << "\n";
00364         stream << "  wUsagePage: " << di.wUsagePage << "\n";
00365         stream << "  wUsage: " << di.wUsage << "\n";
00366 }
00367 
00368 
00369 
00370 void
00371 writeDevCaps
00372 (
00373 IO std::ostream& stream,
00374 IN const DIDEVCAPS& dc
00375 )
00376 {
00377         ASSERT_THROW(stream.good(), "bad stream?");
00378 
00379         stream << "DirectInput device capabilities structure:\n";
00380         stream << "  size: " << dc.dwSize << " bytes\n";
00381         stream << "  flags: ";
00382         writeDCFlags(stream, dc.dwFlags);
00383         stream << "\n";
00384         int type = (int) (dc.dwDevType & 0xff);
00385         int subType = (int) ((dc.dwDevType >> 8) & 0xff);
00386         stream << "  type: " << type << "  subtype: " << subType << "\n";
00387         stream << "  axes: " << dc.dwAxes << "\n";
00388         stream << "  buttons: " << dc.dwButtons << "\n";
00389         stream << "  POVs: " << dc.dwPOVs << "\n";
00390         stream << "  sample period: " << dc.dwFFSamplePeriod << " ms\n";
00391         stream << "  min res: " << dc.dwFFMinTimeResolution << " ms\n";
00392         stream << "  firmware: " << dc.dwFirmwareRevision << "\n";
00393         stream << "  hardware: " << dc.dwHardwareRevision << "\n";
00394         stream << "  ff driver: " << dc.dwFFDriverVersion << "\n";
00395 }
00396 
00397 
00398 
00399 void
00400 writeObjectDataFormat
00401 (
00402 IO std::ostream& stream,
00403 IN const DIOBJECTDATAFORMAT& odf
00404 )
00405 {
00406         ASSERT_THROW(stream.good(), "bad stream?");
00407 
00408         stream << "  DirectInput object data format structure:\n";
00409         stream << "    guid: ";
00410         if (odf.pguid) {
00411                 stream << getGuidName(odf.pguid) << "\n";
00412         } else {
00413                 stream << "(null guid)\n";
00414         }
00415         stream << "    dwOfs: " << odf.dwOfs << " byte offset\n";
00416         stream << "    dwType: ";
00417         writeODFType(stream, odf.dwType);
00418         stream << "\n";
00419         stream << "    dwFlags: ";
00420         writeODFFlags(stream, odf.dwFlags);
00421         stream << "\n";
00422 }
00423 
00424 
00425 
00426 void
00427 writeDataFormat
00428 (
00429 IO std::ostream& stream,
00430 IN const DIDATAFORMAT& df
00431 )
00432 {
00433         ASSERT_THROW(stream.good(), "bad stream?");
00434 
00435         stream << "DirectInput data format structure:\n";
00436         stream << "  dwSize: " << df.dwSize << " bytes\n";
00437         stream << "  dwObjSize: " << df.dwObjSize << " bytes\n";
00438         stream << "  dwFlags: ";
00439         if (DIDF_ABSAXIS == df.dwFlags) {
00440                 stream << "Absolute axes (ABSAXIS)\n";
00441         } else if (DIDF_RELAXIS == df.dwFlags) {
00442                 stream << "Relative axes (RELAXIS)\n";
00443         } else {
00444                 stream << "Unknown flags (" << df.dwFlags << ")\n";
00445         }
00446         stream << "  dwDataSize: " << df.dwDataSize << " bytes\n";
00447         stream << "  dwNumObjs: " << df.dwNumObjs << "\n";
00448         int nObjs = (int) df.dwNumObjs;
00449         for (int i = 0; i < nObjs; ++i) {
00450                 writeObjectDataFormat(stream, df.rgodf[i]);
00451         }
00452 }
00453 
00454 
00455 
00456 void
00457 writeStateDebug
00458 (
00459 IO std::ostream& stream,
00460 IN const DIDATAFORMAT& df,
00461 IN const byte_t * buffer
00462 )
00463 {
00464         ASSERT_THROW(stream.good(), "bad stream");
00465         ASSERT(df.dwSize > 0, "bad size");
00466         ASSERT(df.dwDataSize > 0, "bad data size");
00467         ASSERT(buffer, "null");
00468 
00469         int nObjs = (int) df.dwNumObjs;
00470         DPRINTF("Reading gamepad device state, contains %d objects...", nObjs);
00471         for (int i = 0; i < nObjs; ++i) {
00472                 const DIOBJECTDATAFORMAT& rodf = df.rgodf[i];
00473                 stream << "  Object " << i << ": ";
00474                 stream << "guid=";
00475                 if (rodf.pguid) {
00476                         stream << *rodf.pguid;
00477                 } else {
00478                         stream << "(null)";
00479                 }
00480                 int offset = rodf.dwOfs;
00481                 stream << " offset=" << offset;
00482                 stream << " type=(";
00483                 writeODFType(stream, rodf.dwType);
00484                 stream << ") flags=(";
00485                 writeODFFlags(stream, rodf.dwFlags);
00486                 stream << ") value=";
00487 
00488                 // we assume that only buttons are 1-byte values, and that all
00489                 //      buttons have the BUTTON flag set.  And we furthermore
00490                 //      assume that everything else is a int32 value.
00491                 // Ideally MSDN would mention this information...
00492                 if (DIDFT_BUTTON & rodf.dwType) {
00493                         byte_t b = buffer[offset];
00494                         stream << (int) b;
00495                 } else {
00496                         const int32_t *pl = (const int32_t *) (buffer + offset);
00497                         int32_t val = *pl;
00498                         stream << val;
00499                 }
00500                 stream << "\n";
00501         }
00502 }
00503 
00504 
00505 
00506 void
00507 writeState
00508 (
00509 IO std::ostream& stream,
00510 IN const DIDATAFORMAT& df,
00511 IN const byte_t * buffer
00512 )
00513 {
00514         ASSERT_THROW(stream.good(), "bad stream");
00515         ASSERT(df.dwSize > 0, "bad size");
00516         ASSERT(df.dwDataSize > 0, "bad data size");
00517         ASSERT(buffer, "null");
00518 
00519         int nObjs = (int) df.dwNumObjs;
00520         DPRINTF("Reading gamepad device state, contains %d objects...", nObjs);
00521         for (int i = 0; i < nObjs; ++i) {
00522                 const DIOBJECTDATAFORMAT& rodf = df.rgodf[i];
00523                 int offset = rodf.dwOfs;
00524                 if (DIDFT_BUTTON & rodf.dwType) {
00525                         byte_t b = buffer[offset];
00526                         stream << (int) b;
00527                 } else {
00528                         const int32_t *pl = (const int32_t *) (buffer + offset);
00529                         int32_t val = *pl;
00530                         stream << val;
00531                 }
00532                 stream << " ";
00533         }
00534         stream << "\n";
00535 }
00536 
00537 
00538 
00539 void
00540 device_caps_t::dump
00541 (
00542 IN const char * title
00543 )
00544 const
00545 throw()
00546 {
00547         ASSERT(title, "NULL");
00548         DPRINTF("%s: %d axes, %d POVs, %d buttons",
00549             title, nAxes, nPOVs, nButtons);
00550 }
00551 
00552 
00553 
00554 byte_t *
00555 getDataFormatForDevice
00556 (
00557 IN IDirectInputDevice8 * device,
00558 OUT device_caps_t& dc
00559 )
00560 {
00561         ASSERT(device, "null");
00562         DPRINTF("Constructing data format for device");
00563 
00564         // first we construct our own dynamic array of objects
00565         // next, pack into a data structure that DirectInput understands
00566 
00567         // enumerate all objects on the device (gamepad)
00568         enum_objs_context_t eoc;
00569         device->EnumObjects(objectCallback, &eoc, DIDFT_ALL);
00570         DPRINTF("Found %u objects", eoc.objects.size());
00571  
00572         // construct output array
00573         int nObjs = eoc.objects.size();
00574         int nBytes = sizeof(DIDATAFORMAT) + nObjs * sizeof(DIOBJECTDATAFORMAT) + 2 * sizeof(LPVOID);
00575         byte_t * pb = new byte_t[nBytes];
00576         ASSERT(pb, "out of memory");
00577 
00578         // initialize
00579         DIDATAFORMAT * pdidf = (DIDATAFORMAT *) pb;
00580         pdidf->dwSize = sizeof(DIDATAFORMAT);
00581         pdidf->dwObjSize = sizeof(DIOBJECTDATAFORMAT);
00582         pdidf->dwNumObjs = nObjs;
00583         pdidf->dwDataSize = nObjs * sizeof(dword_t);
00584         pdidf->dwFlags = DIDF_ABSAXIS;
00585 
00586         // weird pointer math: we point to the location in the structure
00587         //      immediately after the pointer itself
00588         long * pl = (long *) &pdidf->rgodf;     // location of pointer
00589         DPRINTF("pl = %p", pl);
00590         ++pl;   // increment just past pointer
00591         pdidf->rgodf = (DIOBJECTDATAFORMAT *) pl;
00592 
00593         // set all of the individual objects
00594         DPRINTF("Setting %d objects...", nObjs);
00595         DIOBJECTDATAFORMAT * p = pdidf->rgodf;
00596         dword_t offset = 0;
00597 
00598         // first pass: axes
00599         for (int i = 0; i < nObjs; ++i) {
00600                 const DIOBJECTDATAFORMAT& obj = eoc.objects[i];
00601                 if (!(DIDFT_AXIS & obj.dwType))
00602                         continue;       // skip this one
00603                 *p = obj;       // copy over to output array
00604                 p->dwOfs = offset;
00605                 offset += sizeof(dword_t);
00606                 ++p;            // next 
00607         }
00608 
00609         // second pass: POVs
00610         for (int i = 0; i < nObjs; ++i) {
00611                 const DIOBJECTDATAFORMAT& obj = eoc.objects[i];
00612                 if (!(DIDFT_POV & obj.dwType))
00613                         continue;       // skip this one
00614                 *p = obj;       // copy over to output array
00615                 p->dwOfs = offset;
00616                 offset += sizeof(dword_t);
00617                 ++p;            // next 
00618         }
00619 
00620         // third pass: buttons
00621         for (int i = 0; i < nObjs; ++i) {
00622                 const DIOBJECTDATAFORMAT& obj = eoc.objects[i];
00623                 if (!(DIDFT_BUTTON & obj.dwType))
00624                         continue;       // skip this one
00625                 *p = obj;       // copy over to output array
00626                 p->dwOfs = offset;
00627                 offset += sizeof(dword_t);
00628                 ++p;            // next 
00629         }
00630 
00631         // verify we exactly filled our data size
00632         offset = (p - pdidf->rgodf);
00633         ASSERT(offset == pdidf->dwNumObjs,
00634             "Mismatch in offset: %d", offset);
00635 
00636         // all done!  Return to caller...
00637         dc = eoc.dc;
00638         dc.dataBytes = pdidf->dwDataSize;
00639 
00640         return pb;
00641 }
00642 
00643 
00644 
00645 
00646 int32_t
00647 getPOVValue
00648 (
00649 IN const byte_t * data,
00650 IN const device_caps_t& dc,
00651 IN int povIndex
00652 )
00653 {
00654         ASSERT(data, "null");
00655         ASSERT(povIndex >= 0 && povIndex < dc.nPOVs,
00656             "Bad pov index: %d", povIndex);
00657 
00658         // get offset in dwords
00659         int offset = dc.nAxes + povIndex;
00660 
00661         // convert to byte offset, and increment data pointer
00662         offset *= sizeof(dword_t);
00663         data += offset;
00664 
00665         // return the int32 pointed to
00666         return *((int32_t *) data);
00667 }
00668 
00669 
00670 
00671 dword_t
00672 getButtonValue
00673 (
00674 IN const byte_t * data,
00675 IN const device_caps_t& dc,
00676 IN int buttonIndex
00677 )
00678 {
00679         ASSERT(data, "null");
00680         ASSERT(buttonIndex >= 0 && buttonIndex < dc.nButtons,
00681             "Invalid button index: %d", buttonIndex);
00682 
00683         // get offset in number of DWORDs
00684         int offset = dc.nAxes + dc.nPOVs + buttonIndex;
00685 
00686         // convert to byte offset and increment the data pointer
00687         offset *= sizeof(dword_t);
00688         data += offset;
00689 
00690         // return the dword at that byte offset
00691         return *((dword_t *) data);
00692 }
00693 
00694 
00695 
00696 int32_t
00697 getAxisValue
00698 (
00699 IN const byte_t * data,
00700 IN const device_caps_t& dc,
00701 IN int axisIndex
00702 )
00703 {
00704         ASSERT(data, "null");
00705         ASSERT(axisIndex >= 0 && axisIndex < dc.nAxes,
00706             "Bad axis index: %d", axisIndex);
00707 
00708         // get offset in DWORDs, convert to bytes
00709         int offset = axisIndex;
00710         offset *= sizeof(dword_t);
00711 
00712         // return value
00713         return *((int32_t *) (data + offset));
00714 }
00715 
00716 
00717 
00718 };      // gamepad namespace