00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 #include "di-diagnostics.h"
00036
00037 #include <iostream>
00038
00039
00040 namespace gamepad {
00041
00042
00043 struct odf_type_entry_t {
00044 dword_t type;
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
00069 { 0, NULL }
00070 };
00071
00072
00073 struct odf_flag_entry_t {
00074 dword_t flag;
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
00088 { 0, NULL }
00089 };
00090
00091
00092 struct dc_flag_entry_t {
00093 dword_t flag;
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
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
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
00153 enum_objs_context_t(void) throw() { this->clear(); }
00154 void clear(void) throw() {
00155 objects.clear();
00156 dc.clear();
00157 }
00158
00159
00160 vec_objdf_t objects;
00161 device_caps_t dc;
00162 };
00163
00164
00165
00166
00167
00168
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
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
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
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
00298 odf.pguid = getGuidPointer(lpddoi->guidType);
00299
00300
00301 peoc->objects.push_back(odf);
00302
00303
00304 return DIENUM_CONTINUE;
00305 }
00306
00307
00308
00309
00310
00311
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
00489
00490
00491
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
00565
00566
00567
00568 enum_objs_context_t eoc;
00569 device->EnumObjects(objectCallback, &eoc, DIDFT_ALL);
00570 DPRINTF("Found %u objects", eoc.objects.size());
00571
00572
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
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
00587
00588 long * pl = (long *) &pdidf->rgodf;
00589 DPRINTF("pl = %p", pl);
00590 ++pl;
00591 pdidf->rgodf = (DIOBJECTDATAFORMAT *) pl;
00592
00593
00594 DPRINTF("Setting %d objects...", nObjs);
00595 DIOBJECTDATAFORMAT * p = pdidf->rgodf;
00596 dword_t offset = 0;
00597
00598
00599 for (int i = 0; i < nObjs; ++i) {
00600 const DIOBJECTDATAFORMAT& obj = eoc.objects[i];
00601 if (!(DIDFT_AXIS & obj.dwType))
00602 continue;
00603 *p = obj;
00604 p->dwOfs = offset;
00605 offset += sizeof(dword_t);
00606 ++p;
00607 }
00608
00609
00610 for (int i = 0; i < nObjs; ++i) {
00611 const DIOBJECTDATAFORMAT& obj = eoc.objects[i];
00612 if (!(DIDFT_POV & obj.dwType))
00613 continue;
00614 *p = obj;
00615 p->dwOfs = offset;
00616 offset += sizeof(dword_t);
00617 ++p;
00618 }
00619
00620
00621 for (int i = 0; i < nObjs; ++i) {
00622 const DIOBJECTDATAFORMAT& obj = eoc.objects[i];
00623 if (!(DIDFT_BUTTON & obj.dwType))
00624 continue;
00625 *p = obj;
00626 p->dwOfs = offset;
00627 offset += sizeof(dword_t);
00628 ++p;
00629 }
00630
00631
00632 offset = (p - pdidf->rgodf);
00633 ASSERT(offset == pdidf->dwNumObjs,
00634 "Mismatch in offset: %d", offset);
00635
00636
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
00659 int offset = dc.nAxes + povIndex;
00660
00661
00662 offset *= sizeof(dword_t);
00663 data += offset;
00664
00665
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
00684 int offset = dc.nAxes + dc.nPOVs + buttonIndex;
00685
00686
00687 offset *= sizeof(dword_t);
00688 data += offset;
00689
00690
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
00709 int offset = axisIndex;
00710 offset *= sizeof(dword_t);
00711
00712
00713 return *((int32_t *) (data + offset));
00714 }
00715
00716
00717
00718 };