Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2484 lines
82 KiB

  1. /*****************************************************************************
  2. *
  3. * DIDevDf.c
  4. *
  5. * Copyright (c) 1996 Microsoft Corporation. All Rights Reserved.
  6. *
  7. * Abstract:
  8. *
  9. * The part of IDirectInputDevice that worries about
  10. * data formats and reading device data.
  11. *
  12. *****************************************************************************/
  13. #include "dinputpr.h"
  14. #include "didev.h"
  15. int INTERNAL
  16. CDIDev_OffsetToIobj(PDD this, DWORD dwOfs);
  17. /*****************************************************************************
  18. *
  19. * @doc INTERNAL
  20. *
  21. * @func HRESULT | CDIDev_GetAbsDeviceState |
  22. *
  23. * Get the absolute device state.
  24. *
  25. * @parm OUT LPVOID | pvData |
  26. *
  27. * Application-provided output buffer.
  28. *
  29. *****************************************************************************/
  30. STDMETHODIMP
  31. CDIDev_GetAbsDeviceState(PDD this, LPVOID pvData)
  32. {
  33. return this->pdcb->lpVtbl->GetDeviceState(this->pdcb, pvData);
  34. }
  35. /*****************************************************************************
  36. *
  37. * @doc INTERNAL
  38. *
  39. * @func HRESULT | CDIDev_GetRelDeviceState |
  40. *
  41. * Get the relative device state.
  42. *
  43. * @parm OUT LPVOID | pvData |
  44. *
  45. * Application-provided output buffer.
  46. *
  47. *****************************************************************************/
  48. STDMETHODIMP
  49. CDIDev_GetRelDeviceState(PDD this, LPVOID pvData)
  50. {
  51. HRESULT hres;
  52. hres = this->pdcb->lpVtbl->GetDeviceState(this->pdcb, pvData);
  53. if ( SUCCEEDED(hres) ) {
  54. UINT iaxis;
  55. AssertF(fLimpFF(this->cAxes, this->pvLastBuffer && this->rgdwAxesOfs));
  56. /*
  57. * For each axis, replace the app's buffer with the delta,
  58. * and save the old value.
  59. */
  60. for ( iaxis = 0; iaxis < this->cAxes; iaxis++ ) {
  61. LONG UNALIGNED *plApp = pvAddPvCb(pvData, this->rgdwAxesOfs[iaxis]);
  62. LONG UNALIGNED *plLast = pvAddPvCb(this->pvLastBuffer,
  63. this->rgdwAxesOfs[iaxis]);
  64. LONG lNew = *plApp;
  65. *plApp -= *plLast;
  66. *plLast = lNew;
  67. }
  68. hres = S_OK;
  69. }
  70. return hres;
  71. }
  72. /*****************************************************************************
  73. *
  74. * @doc INTERNAL
  75. *
  76. * @func HRESULT | CDIDev_GetDeviceStateSlow |
  77. *
  78. * Obtains data from the DirectInput device the slow way.
  79. *
  80. * Read the data into the private buffer, then copy it
  81. * bit by bit into the application's buffer.
  82. *
  83. * @parm OUT LPVOID | lpvData |
  84. *
  85. * Application-provided output buffer.
  86. *
  87. *****************************************************************************/
  88. STDMETHODIMP
  89. CDIDev_GetDeviceStateSlow(PDD this, LPVOID pvData)
  90. {
  91. HRESULT hres;
  92. EnterProcR(IDirectInputDevice::GetDeviceStateSlow, (_ "pp", this, pvData));
  93. AssertF(this->diopt == dioptNone);
  94. AssertF(this->pvBuffer);
  95. AssertF(this->pdcb);
  96. hres = this->GetDeviceState(this, this->pvBuffer);
  97. if ( SUCCEEDED(hres) ) {
  98. int iobj;
  99. ZeroMemory(pvData, this->dwDataSize);
  100. for ( iobj = this->df.dwNumObjs; --iobj >= 0; ) {
  101. if ( this->pdix[iobj].dwOfs != 0xFFFFFFFF ) { /* Data was requested */
  102. DWORD UNALIGNED *pdwOut = pvAddPvCb(pvData, this->pdix[iobj].dwOfs);
  103. DWORD UNALIGNED *pdwIn = pvAddPvCb(this->pvBuffer, this->df.rgodf[iobj].dwOfs);
  104. if ( this->df.rgodf[iobj].dwType & DIDFT_DWORDOBJS ) {
  105. *pdwOut = *pdwIn;
  106. } else {
  107. *(LPBYTE)pdwOut = *(LPBYTE)pdwIn;
  108. }
  109. }
  110. }
  111. }
  112. ExitOleProc();
  113. return hres;
  114. }
  115. /*****************************************************************************
  116. *
  117. * @doc INTERNAL
  118. *
  119. * @func HRESULT | CDIDev_GetDeviceStateMatched |
  120. *
  121. * Obtains data from the DirectInput device in the case
  122. * where the data formats are matched.
  123. *
  124. * Read the data into the private buffer, then block copy it
  125. * into the application's buffer.
  126. *
  127. * @parm OUT LPVOID | lpvData |
  128. *
  129. * Application-provided output buffer.
  130. *
  131. *****************************************************************************/
  132. STDMETHODIMP
  133. CDIDev_GetDeviceStateMatched(PDD this, LPVOID pvData)
  134. {
  135. HRESULT hres;
  136. EnterProcR(IDirectInputDevice::GetDeviceStateMatched, (_ "pp", this, pvData));
  137. AssertF(this->diopt == dioptMatch);
  138. AssertF(this->pvBuffer);
  139. AssertF(this->pdcb);
  140. hres = this->GetDeviceState(this, this->pvBuffer);
  141. if ( SUCCEEDED(hres) ) {
  142. /*
  143. * To keep keyboard clients happy: Zero out the fore and aft.
  144. * No need to optimize the perfect match case, because that
  145. * gets a different optimization level.
  146. */
  147. ZeroMemory(pvData, this->dwDataSize);
  148. memcpy(pvAddPvCb(pvData, this->ibDelta + this->ibMin),
  149. pvAddPvCb(this->pvBuffer, this->ibMin), this->cbMatch);
  150. }
  151. ExitOleProc();
  152. return hres;
  153. }
  154. /*****************************************************************************
  155. *
  156. * @doc INTERNAL
  157. *
  158. * @func HRESULT | CDIDev_GetDeviceStateDirect |
  159. *
  160. * Obtains data from the DirectInput device in the case
  161. * where we can read the data directly into the client buffer.
  162. *
  163. * @parm OUT LPVOID | lpvData |
  164. *
  165. * Application-provided output buffer.
  166. *
  167. *****************************************************************************/
  168. STDMETHODIMP
  169. CDIDev_GetDeviceStateDirect(PDD this, LPVOID pvData)
  170. {
  171. HRESULT hres;
  172. EnterProcR(IDirectInputDevice::GetDeviceStateDirect, (_ "pp", this, pvData));
  173. AssertF(this->diopt == dioptDirect);
  174. AssertF(!this->pvBuffer);
  175. AssertF(this->pdcb);
  176. /*
  177. * To keep keyboard clients happy: Zero out the fore and aft.
  178. */
  179. ZeroBuf(pvData, this->dwDataSize);
  180. hres = this->GetDeviceState(this, pvAddPvCb(pvData, this->ibDelta));
  181. ExitOleProc();
  182. return hres;
  183. }
  184. /*****************************************************************************
  185. *
  186. * @doc INTERNAL
  187. *
  188. * @func HRESULT | CDIDev_GetDeviceStateEqual |
  189. *
  190. * Obtains data from the DirectInput device in the case
  191. * where the two data formats are completely identical.
  192. *
  193. * @parm OUT LPVOID | lpvData |
  194. *
  195. * Application-provided output buffer.
  196. *
  197. *****************************************************************************/
  198. STDMETHODIMP
  199. CDIDev_GetDeviceStateEqual(PDD this, LPVOID pvData)
  200. {
  201. HRESULT hres;
  202. EnterProcR(IEqualInputDevice::GetDeviceStateEqual, (_ "pp", this, pvData));
  203. AssertF(this->diopt == dioptEqual);
  204. AssertF(this->ibDelta == 0);
  205. AssertF(this->dwDataSize == this->df.dwDataSize);
  206. AssertF(!this->pvBuffer);
  207. AssertF(this->pdcb);
  208. /*
  209. * Note that this->ibMin is not necessarily zero if the device
  210. * data format doesn't begin at zero (which keyboards don't).
  211. */
  212. hres = this->GetDeviceState(this, pvData);
  213. ExitOleProc();
  214. return hres;
  215. }
  216. /*****************************************************************************
  217. *
  218. * @doc INTERNAL
  219. *
  220. * @method BOOL | CDIDev | IsMatchingGUID |
  221. *
  222. * Helper function that checks if a <t GUID> counts as
  223. * a match when parsing the data format.
  224. *
  225. * @parm PCGUID | pguidSrc |
  226. *
  227. * The <t GUID> to check.
  228. *
  229. * @parm PCGUID | pguidDst |
  230. *
  231. * The <t GUID> it should match.
  232. *
  233. * @returns
  234. *
  235. * Nonzero if this counts as a success.
  236. *
  237. *****************************************************************************/
  238. #pragma BEGIN_CONST_DATA
  239. GUID GUID_Null; /* A zero-filled guid */
  240. #pragma END_CONST_DATA
  241. BOOL INLINE
  242. CDIDev_IsMatchingGUID(PDD this, PCGUID pguidSrc, PCGUID pguidDst)
  243. {
  244. return IsEqualGUID(pguidSrc, &GUID_Null) ||
  245. IsEqualGUID(pguidSrc, pguidDst);
  246. }
  247. /*****************************************************************************
  248. *
  249. * @doc INTERNAL
  250. *
  251. * @method BOOL | CDIDev | IsMatchingUsage |
  252. *
  253. * Helper function that checks if a <f DIMAKEUSAGEDWORD>
  254. * counts as a match when parsing the data format.
  255. *
  256. * @parm DWORD | dwUsage |
  257. *
  258. * The <f DIMAKEUSAGEDWORD> to check.
  259. *
  260. * @parm int | iobj |
  261. *
  262. * The index of hte object to check for a match.
  263. *
  264. * @returns
  265. *
  266. * Nonzero if this counts as a success.
  267. *
  268. *****************************************************************************/
  269. BOOL INLINE
  270. CDIDev_IsMatchingUsage(PDD this, DWORD dwUsage, int iobj)
  271. {
  272. AssertF(this->pdcb);
  273. return dwUsage == this->pdcb->lpVtbl->GetUsage(this->pdcb, iobj);
  274. }
  275. /*****************************************************************************
  276. *
  277. * @doc INTERNAL
  278. *
  279. * @method int | CDIDev | FindDeviceObjectFormat |
  280. *
  281. * Search the device object format table for the one that
  282. * matches the guid in question.
  283. *
  284. * @parm PCODF | podf |
  285. *
  286. * The object to locate. If the <e DIOBJECTDATAFORMAT.rguid>
  287. * is null, then the field is a wildcard.
  288. *
  289. * If the <e DIOBJECTDATAFORMAT.dwType> specifies
  290. * <c DIDFT_ANYINSTANCE>, then any instance will be accepted.
  291. *
  292. * @parm PDIXLAT | pdix |
  293. *
  294. * The partial translation table so far. This is used to find
  295. * an empty slot in case of wildcards.
  296. *
  297. * @returns
  298. *
  299. * Returns the index of the object that matches, or -1 if
  300. * the object is not supported by the device.
  301. *
  302. * Someday: Should fall back to best match if types don't match.
  303. *
  304. *****************************************************************************/
  305. int INTERNAL
  306. CDIDev_FindDeviceObjectFormat(PDD this, PCODF podf, PDIXLAT pdix)
  307. {
  308. PCODF podfD; /* The format in the device */
  309. UINT iobj;
  310. /*
  311. * We must count upwards, so that first-fit chooses the smallest one.
  312. */
  313. for ( iobj = 0; iobj < this->df.dwNumObjs; iobj++ ) {
  314. podfD = &this->df.rgodf[iobj];
  315. if (
  316. /*
  317. * Type needs to match.
  318. *
  319. * Note that works for output-only actuators:
  320. * Since you cannot read from an output-only
  321. * actuator, you can't put it in a data format.
  322. *
  323. */
  324. (podf->dwType & DIDFT_TYPEVALID & podfD->dwType)
  325. /*
  326. * Attributes need to match.
  327. */
  328. && fHasAllBitsFlFl(podfD->dwType, podf->dwType & DIDFT_ATTRVALID)
  329. /*
  330. * Slot needs to be empty.
  331. */
  332. && pdix[iobj].dwOfs == 0xFFFFFFFF
  333. /*
  334. * "If there is a guid/usage, it must match."
  335. *
  336. * If pguid is NULL, then the match is vacuous.
  337. *
  338. * If DIDOI_GUIDISUSAGE is clear, then pguid points to
  339. * a real GUID. GUID_NULL means "Don't care" and matches
  340. * anything. Otherwise, it must match the actual GUID.
  341. *
  342. * If DIDOI_GUIDISUSAGE is set, then pguid is really
  343. * a DIMAKEUSAGEDWORD of the usage and usage page,
  344. * which we compare against the same in the object.
  345. */
  346. && (podf->pguid == 0 ||
  347. ((podf->dwFlags & DIDOI_GUIDISUSAGE) ?
  348. CDIDev_IsMatchingUsage(this, (DWORD)(UINT_PTR)podf->pguid, iobj) :
  349. CDIDev_IsMatchingGUID(this, podf->pguid, podfD->pguid)))
  350. /*
  351. * If there is an instance number, it must match.
  352. *
  353. * Note that we need to be careful how we check, because
  354. * DX 3.0 and DX 5.0 uses different masks. (DX 5.0 needs
  355. * 16 bits of instance data to accomodate HID devices.)
  356. */
  357. && fLimpFF((podf->dwType & this->didftInstance) !=
  358. this->didftInstance,
  359. fEqualMaskFlFl(this->didftInstance,
  360. podf->dwType, podfD->dwType))
  361. /*
  362. * If there is an aspect, it must match.
  363. *
  364. * If the device data format doesn't specify an aspect,
  365. * then that counts as a free match too.
  366. */
  367. && fLimpFF((podf->dwFlags & DIDOI_ASPECTMASK) &&
  368. (podfD->dwFlags & DIDOI_ASPECTMASK),
  369. fEqualMaskFlFl(DIDOI_ASPECTMASK,
  370. podf->dwFlags, podfD->dwFlags))
  371. ) { /* Criterion matches, woo-hoo */
  372. return iobj;
  373. }
  374. }
  375. return -1;
  376. }
  377. /*****************************************************************************
  378. *
  379. * @doc INTERNAL
  380. *
  381. * @method HRESULT | CDIDev | ParseDataFormat |
  382. *
  383. * Parse the data format passed by the application and
  384. * convert it into a format that we can use to translate
  385. * the device data into application data.
  386. *
  387. * @parm IN LPDIDATAFORMAT | lpdf |
  388. *
  389. * Points to a structure that describes the format of the data
  390. * the DirectInputDevice should return.
  391. *
  392. * @returns
  393. *
  394. * Returns a COM error code. The following error codes are
  395. * intended to be illustrative and not necessarily comprehensive.
  396. *
  397. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  398. *
  399. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: The
  400. * <p lpvData> parameter is not a valid pointer.
  401. *
  402. * <c DIERR_ACQUIRED>: Cannot change the data format while the
  403. * device is acquired.
  404. *
  405. *
  406. *****************************************************************************/
  407. STDMETHODIMP
  408. CDIDev_ParseDataFormat(PDD this, const DIDATAFORMAT *lpdf)
  409. {
  410. PDIXLAT pdix;
  411. // Prefix Whistler: 45081
  412. PINT rgiobj = NULL;
  413. HRESULT hres;
  414. DIPROPDWORD dipdw;
  415. VXDDATAFORMAT vdf;
  416. DWORD dwDataSize;
  417. #ifdef DEBUG
  418. EnterProc(CDIDev_ParseDataFormat, (_ "pp", this, lpdf));
  419. #else
  420. EnterProcR(IDirectInputDevice::SetDataFormat, (_ "pp", this, lpdf));
  421. #endif
  422. /*
  423. * Caller should've nuked the old translation table.
  424. */
  425. AssertF(this->pdix == 0);
  426. AssertF(this->rgiobj == 0);
  427. AssertF(this->cdwPOV == 0);
  428. vdf.cbData = this->df.dwDataSize;
  429. vdf.pDfOfs = 0;
  430. /*
  431. * If the device is cooked, then we stash the client offset
  432. * into the high word of the VxD data, so it had better fit into
  433. * a word...
  434. */
  435. dwDataSize = min(lpdf->dwDataSize, 0x00010000);
  436. if ( SUCCEEDED(hres = AllocCbPpv(cbCxX(this->df.dwNumObjs, DIXLAT), &pdix)) &&
  437. SUCCEEDED(hres = AllocCbPpv(cbCdw(this->df.dwDataSize), &vdf.pDfOfs)) &&
  438. SUCCEEDED(hres = AllocCbPpv(cbCdw(lpdf->dwDataSize), &rgiobj)) &&
  439. SUCCEEDED(hres =
  440. ReallocCbPpv(cbCdw(lpdf->dwNumObjs), &this->rgdwPOV)) ) {
  441. UINT iobj;
  442. /*
  443. * Pre-init all the translation tags to -1,
  444. * which means "not in use"
  445. */
  446. memset(pdix, 0xFF, cbCxX(this->df.dwNumObjs, DIXLAT));
  447. memset(vdf.pDfOfs, 0xFF, cbCdw(this->df.dwDataSize));
  448. memset(rgiobj, 0xFF, cbCdw(lpdf->dwDataSize));
  449. SquirtSqflPtszV(sqflDf, TEXT("Begin parse data format"));
  450. for ( iobj = 0; iobj < lpdf->dwNumObjs; iobj++ ) {
  451. PCODF podf = &lpdf->rgodf[iobj];
  452. SquirtSqflPtszV(sqflDf, TEXT("Object %2d: offset %08x"),
  453. iobj, podf->dwOfs);
  454. /*
  455. * Note that the podf->dwOfs < dwDataSize test is safe
  456. * even for DWORD objects, since we also check that both
  457. * values are DWORD multiples.
  458. */
  459. if ( ((podf->dwFlags & DIDOI_GUIDISUSAGE) ||
  460. fLimpFF(podf->pguid,
  461. SUCCEEDED(hres = hresFullValidGuid(podf->pguid, 1)))) &&
  462. podf->dwOfs < dwDataSize ) {
  463. int iobjDev = CDIDev_FindDeviceObjectFormat(this, podf, pdix);
  464. /* Hack for pre DX6 apps that only look for a Z axis,
  465. * newer USB devices use GUID_Slider for the same functionality.
  466. *
  467. */
  468. if ( podf->pguid != 0x0 // Looking for matching GUID
  469. && this->dwVersion < 0x600 // Only for Dx version < 0x600
  470. && iobjDev == -1 // Did not find default mapping
  471. && IsEqualGUID(podf->pguid, &GUID_ZAxis) ) // Looking for GUID_ZAxis
  472. {
  473. ODF odf = lpdf->rgodf[iobj]; // Make a copy of the object data format
  474. odf.pguid = &GUID_Slider; // Substitute Slider for Z axis
  475. iobjDev = CDIDev_FindDeviceObjectFormat(this, &odf, pdix);
  476. }
  477. if ( iobjDev != -1 ) {
  478. PCODF podfFound = &this->df.rgodf[iobjDev];
  479. if ( podfFound->dwType & DIDFT_DWORDOBJS ) {
  480. if ( (podf->dwOfs & 3) == 0 ) {
  481. } else {
  482. RPF("%s: Dword objects must be aligned", s_szProc);
  483. goto fail;
  484. }
  485. }
  486. if ( this->fCook ) {
  487. vdf.pDfOfs[podfFound->dwOfs] =
  488. (DWORD)DICOOK_DFOFSFROMOFSID(podf->dwOfs,
  489. podfFound->dwType);
  490. } else {
  491. vdf.pDfOfs[podfFound->dwOfs] = podf->dwOfs;
  492. }
  493. pdix[iobjDev].dwOfs = podf->dwOfs;
  494. rgiobj[podf->dwOfs] = iobjDev;
  495. if ( podfFound->dwFlags & DIDOI_POLLED ) {
  496. this->fPolledDataFormat = TRUE;
  497. }
  498. dipdw.diph.dwSize = sizeof(DIPROPDWORD);
  499. dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
  500. dipdw.diph.dwObj = podfFound->dwType;
  501. dipdw.diph.dwHow = DIPH_BYID;
  502. dipdw.dwData = 0x1; // Enable this report ID
  503. hres = CDIDev_RealSetProperty(this, DIPROP_ENABLEREPORTID, &dipdw.diph);
  504. if ( hres == E_NOTIMPL )
  505. {
  506. SquirtSqflPtszV(sqflDf,
  507. TEXT("Could not set DIPROP_ENABLEREPORTID for offset %d"),
  508. iobj);
  509. hres = S_OK;
  510. }
  511. } else if ( podf->dwType & DIDFT_OPTIONAL ) {
  512. SquirtSqflPtszV(sqflDf,
  513. TEXT("Object %2d: Skipped (optional)"),
  514. iobj);
  515. /*
  516. * We need to remember where the failed POVs live
  517. * so we can neutralize them in GetDeviceState().
  518. */
  519. if ( podf->dwType & DIDFT_POV ) {
  520. AssertF(this->cdwPOV < lpdf->dwNumObjs);
  521. this->rgdwPOV[this->cdwPOV++] = podf->dwOfs;
  522. }
  523. } else {
  524. RPF("%s: Format not compatible with device", s_szProc);
  525. goto fail;
  526. }
  527. } else {
  528. if ( podf->dwOfs >= lpdf->dwDataSize ) {
  529. RPF("%s: Offset out of range in data format", s_szProc);
  530. } else if ( podf->dwOfs >= dwDataSize ) {
  531. RPF("%s: Data format cannot exceed 64K", s_szProc);
  532. }
  533. fail:;
  534. hres = E_INVALIDARG;
  535. goto done;
  536. }
  537. }
  538. #ifdef DEBUG
  539. /*
  540. * Double-check the lookup tables just to preserve our sanity.
  541. */
  542. {
  543. UINT dwOfs;
  544. for ( dwOfs = 0; dwOfs < lpdf->dwDataSize; dwOfs++ ) {
  545. if ( rgiobj[dwOfs] >= 0 ) {
  546. AssertF(pdix[rgiobj[dwOfs]].dwOfs == dwOfs);
  547. } else {
  548. AssertF(rgiobj[dwOfs] == -1);
  549. }
  550. }
  551. }
  552. #endif
  553. /*
  554. * Shrink the "failed POV" array to its actual size.
  555. * The shrink "should" always succeed. Note also that
  556. * even if it fails, we're okay; we just waste a little
  557. * memory.
  558. */
  559. hres = ReallocCbPpv(cbCdw(this->cdwPOV), &this->rgdwPOV);
  560. AssertF(SUCCEEDED(hres));
  561. /*
  562. * If we are using cooked data, then we actually hand the
  563. * device driver a different translation table which
  564. * combines the offset and dwDevType so data cooking can
  565. * happen safely.
  566. */
  567. vdf.pvi = this->pvi;
  568. if ( fLimpFF(this->pvi,
  569. SUCCEEDED(hres = Hel_SetDataFormat(&vdf))) ) {
  570. this->pdix = pdix;
  571. pdix = 0;
  572. this->rgiobj = rgiobj;
  573. rgiobj = 0;
  574. this->dwDataSize = lpdf->dwDataSize;
  575. hres = S_OK;
  576. } else {
  577. AssertF(FAILED(hres));
  578. }
  579. } else {
  580. /* Out of memory */
  581. }
  582. done:;
  583. FreePpv(&pdix);
  584. FreePpv(&rgiobj);
  585. FreePpv(&vdf.pDfOfs);
  586. ExitOleProc();
  587. return hres;
  588. }
  589. #ifdef BUGGY_DX7_WINNT
  590. /*****************************************************************************
  591. *
  592. * @doc INTERNAL
  593. *
  594. * @method HRESULT | CDIDev | ParseDataFormatInternal |
  595. *
  596. * Parse the data format passed by CDIDev_Intialize and
  597. * convert it into a format that we can use to translate
  598. * the device data into application data. Used on WINNT only.
  599. *
  600. * @parm IN LPDIDATAFORMAT | lpdf |
  601. *
  602. * Points to a structure that describes the format of the data
  603. * the DirectInputDevice should return.
  604. *
  605. * @returns
  606. *
  607. * Returns a COM error code. The following error codes are
  608. * intended to be illustrative and not necessarily comprehensive.
  609. *
  610. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  611. *
  612. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: The
  613. * <p lpvData> parameter is not a valid pointer.
  614. *
  615. * <c DIERR_ACQUIRED>: Cannot change the data format while the
  616. * device is acquired.
  617. *
  618. * @devnotes:
  619. * This function is originaly wrote to fix manbug: 41464.
  620. * Boarder Zone gets object's data offset before it calls SetDataFormat,
  621. * so Dinput returns it internal data offsets. But it uses them as user data
  622. * offset, which causes the bug.
  623. * To fix it, we call this function in CDIDev_Initialize with c_dfDIJoystick,
  624. * which is used by many games. When an application ask for object info,
  625. * we check if an user data format has been set, if not, we will assume user
  626. * uses c_dfDIJoystick, hence return the data offset based on it.
  627. * This function will only be called if application uses dinput (version < 0x700)
  628. * && (version != 0x5B2).
  629. *
  630. *****************************************************************************/
  631. HRESULT CDIDev_ParseDataFormatInternal(PDD this, const DIDATAFORMAT *lpdf)
  632. {
  633. PDIXLAT pdix;
  634. PINT rgiobj = NULL;
  635. HRESULT hres;
  636. #ifdef DEBUG
  637. EnterProc(CDIDev_ParseDataFormat2, (_ "pp", this, lpdf));
  638. #endif
  639. AssertF(this->pdix2 == 0);
  640. if( SUCCEEDED(hres = AllocCbPpv(cbCxX(this->df.dwNumObjs, DIXLAT), &pdix)) &&
  641. SUCCEEDED(hres = AllocCbPpv(cbCdw(lpdf->dwDataSize), &rgiobj)))
  642. {
  643. UINT iobj;
  644. /*
  645. * Pre-init all the translation tags to -1,
  646. * which means "not in use"
  647. */
  648. memset(pdix, 0xFF, cbCxX(this->df.dwNumObjs, DIXLAT));
  649. memset(rgiobj, 0xFF, cbCdw(lpdf->dwDataSize));
  650. for ( iobj = 0; iobj < lpdf->dwNumObjs; iobj++ ) {
  651. PCODF podf = &lpdf->rgodf[iobj];
  652. SquirtSqflPtszV(sqflDf | sqflVerbose, TEXT("Object %2d: offset %08x"),
  653. iobj, podf->dwOfs);
  654. /*
  655. * Note that the podf->dwOfs < lpdf->dwDataSize test is safe
  656. * even for DWORD objects, since we also check that both
  657. * values are DWORD multiples.
  658. */
  659. if ( ((podf->dwFlags & DIDOI_GUIDISUSAGE) ||
  660. fLimpFF(podf->pguid,
  661. SUCCEEDED(hres = hresFullValidGuid(podf->pguid, 1)))) &&
  662. podf->dwOfs < lpdf->dwDataSize ) {
  663. int iobjDev = CDIDev_FindDeviceObjectFormat(this, podf, pdix);
  664. if ( iobjDev != -1 ) {
  665. PCODF podfFound = &this->df.rgodf[iobjDev];
  666. if ( podfFound->dwType & DIDFT_DWORDOBJS ) {
  667. if ( (podf->dwOfs & 3) == 0 ) {
  668. } else {
  669. RPF("%s: Dword objects must be aligned", s_szProc);
  670. goto fail;
  671. }
  672. }
  673. pdix[iobjDev].dwOfs = podf->dwOfs;
  674. rgiobj[podf->dwOfs] = iobjDev;
  675. } else if ( podf->dwType & DIDFT_OPTIONAL ) {
  676. //do nothing
  677. } else {
  678. RPF("%s: Format not compatible with device", s_szProc);
  679. goto fail;
  680. }
  681. } else {
  682. if ( podf->dwOfs >= lpdf->dwDataSize ) {
  683. RPF("%s: rgodf[%d].dwOfs of 0x%08x out of range in data format",
  684. s_szProc, iobj, podf->dwOfs );
  685. }
  686. fail:;
  687. hres = E_INVALIDARG;
  688. goto done;
  689. }
  690. }
  691. #ifdef DEBUG
  692. /*
  693. * Double-check the lookup tables just to preserve our sanity.
  694. */
  695. {
  696. UINT dwOfs;
  697. for ( dwOfs = 0; dwOfs < lpdf->dwDataSize; dwOfs++ ) {
  698. if ( rgiobj[dwOfs] >= 0 ) {
  699. AssertF(pdix[rgiobj[dwOfs]].dwOfs == dwOfs);
  700. } else {
  701. AssertF(rgiobj[dwOfs] == -1);
  702. }
  703. }
  704. }
  705. #endif
  706. this->pdix2 = pdix;
  707. pdix = 0;
  708. this->rgiobj2 = rgiobj;
  709. rgiobj = 0;
  710. this->dwDataSize2 = lpdf->dwDataSize;
  711. hres = S_OK;
  712. } else {
  713. /* Out of memory */
  714. hres = ERROR_NOT_ENOUGH_MEMORY;
  715. }
  716. done:;
  717. FreePpv(&pdix);
  718. FreePpv(&rgiobj);
  719. ExitOleProc();
  720. return hres;
  721. }
  722. #endif //BUGGY_DX7_WINNT
  723. /*****************************************************************************
  724. *
  725. * @doc INTERNAL
  726. *
  727. * @method HRESULT | CDIDev | OptimizeDataFormat |
  728. *
  729. * Study the parsed data format to determine whether we can
  730. * used an optimized <mf CDIDev::GetDeviceState> to obtain
  731. * the data more quickly.
  732. *
  733. * The data format is considered optimized if it matches the
  734. * device data format, modulo possible shifting due to insertion
  735. * of bonus fields at the beginning or end, and modulo missing
  736. * fields.
  737. *
  738. * The data format is considered fully-optimized if it
  739. * optimized, and no shifting is necessary, and the structure size
  740. * is exactly the same. This means the buffer can be passed
  741. * straight through to the driver.
  742. *
  743. *
  744. *****************************************************************************/
  745. HRESULT INTERNAL
  746. CDIDev_OptimizeDataFormat(PDD this)
  747. {
  748. int ib;
  749. DWORD ibMax; /* One past highest match point */
  750. DWORD ibMin; /* Lowest match point */
  751. int iobj;
  752. DWORD dwDataSize;
  753. HRESULT hres;
  754. EnterProc(CDIDev_OptimizeDataFormat, (_ "p", this));
  755. ib = -1; /* Not yet known */
  756. ibMin = 0xFFFFFFFF;
  757. ibMax = 0;
  758. /*
  759. * ISSUE-2001/03/29-timgill Need to change data sentinel value
  760. * -1 is not a valid sentinel; we might validly
  761. * get data at an offset of -1.
  762. */
  763. for ( iobj = this->df.dwNumObjs; --iobj >= 0; ) {
  764. DWORD ibMaxThis;
  765. if ( this->pdix[iobj].dwOfs != 0xFFFFFFFF ) { /* Data was requested */
  766. int ibExpected = (int)(this->pdix[iobj].dwOfs -
  767. this->df.rgodf[iobj].dwOfs);
  768. if ( fLimpFF(ib != -1, ib == ibExpected) ) {
  769. ib = ibExpected;
  770. } else {
  771. SquirtSqflPtszV(sqfl | sqflMajor,
  772. TEXT("IDirectInputDevice: Optimization level 0, translation needed") );
  773. this->diopt = dioptNone;
  774. this->GetState = CDIDev_GetDeviceStateSlow;
  775. goto done;
  776. }
  777. if ( ibMin > this->df.rgodf[iobj].dwOfs ) {
  778. ibMin = this->df.rgodf[iobj].dwOfs;
  779. }
  780. if ( this->df.rgodf[iobj].dwType & DIDFT_DWORDOBJS ) {
  781. ibMaxThis = this->df.rgodf[iobj].dwOfs + sizeof(DWORD);
  782. } else {
  783. ibMaxThis = this->df.rgodf[iobj].dwOfs + sizeof(BYTE);
  784. }
  785. if ( ibMax < ibMaxThis ) {
  786. ibMax = ibMaxThis;
  787. }
  788. }
  789. }
  790. /*
  791. * Make sure we actually found something.
  792. */
  793. if ( ib != -1 ) { /* Data format is matched */
  794. AssertF(ibMin < ibMax);
  795. AssertF( ib + (int)ibMin >= 0);
  796. AssertF(ib + ibMax <= this->dwDataSize);
  797. this->ibDelta = ib;
  798. this->ibMin = ibMin;
  799. this->cbMatch = ibMax - ibMin;
  800. if ( ib >= 0 && ib + this->df.dwDataSize <= this->dwDataSize ) {
  801. /* We can go direct */
  802. if ( ib == 0 && this->dwDataSize == this->df.dwDataSize ) {
  803. /* Data formats are equal! */
  804. this->diopt = dioptEqual;
  805. this->GetState = CDIDev_GetDeviceStateEqual;
  806. SquirtSqflPtszV(sqfl | sqflMajor,
  807. TEXT("IDirectInputDevice: Optimization level 3, full speed ahead!") );
  808. } else {
  809. this->diopt = dioptDirect;
  810. this->GetState = CDIDev_GetDeviceStateDirect;
  811. SquirtSqflPtszV(sqfl | sqflMajor,
  812. TEXT("IDirectInputDevice: Optimization level 2, direct access") );
  813. }
  814. } else {
  815. SquirtSqflPtszV(sqfl | sqflMajor,
  816. TEXT("IDirectInputDevice: Optimization level 1, okay") );
  817. this->diopt = dioptMatch;
  818. this->GetState = CDIDev_GetDeviceStateMatched;
  819. }
  820. } else { /* No data in data format! */
  821. RPF("IDirectInputDevice: Null data format; if that's what you want...");
  822. this->diopt = dioptNone;
  823. this->GetState = CDIDev_GetDeviceStateSlow;
  824. }
  825. done:;
  826. if ( this->diopt >= dioptDirect ) { /* Can go direct; don't need buf */
  827. dwDataSize = 0;
  828. } else {
  829. dwDataSize = this->df.dwDataSize;
  830. }
  831. hres = ReallocCbPpv(dwDataSize, &this->pvBuffer);
  832. if ( SUCCEEDED(hres) ) {
  833. AssertF(this->GetState);
  834. } else {
  835. FreePpv(&this->pdix);
  836. D(this->GetState = 0);
  837. }
  838. return hres;
  839. }
  840. /*****************************************************************************
  841. *
  842. * @doc EXTERNAL
  843. *
  844. * @method HRESULT | IDirectInputDevice | SetDataFormat |
  845. *
  846. * Set the data format for the DirectInput device.
  847. *
  848. * The data format must be set before the device can be
  849. * acquired.
  850. *
  851. * It is necessary to set the data format only once.
  852. *
  853. * The data format may not be changed while the device
  854. * is acquired.
  855. *
  856. * If the attempt to set the data format fails, all data
  857. * format information is lost, and a valid data format
  858. * must be set before the device may be acquired.
  859. *
  860. * @cwrap LPDIRECTINPUTDEVICE | lpDirectInputDevice
  861. *
  862. * @parm IN LPDIDATAFORMAT | lpdf |
  863. *
  864. * Points to a structure that describes the format of the data
  865. * the DirectInputDevice should return.
  866. *
  867. * @returns
  868. *
  869. * Returns a COM error code. The following error codes are
  870. * intended to be illustrative and not necessarily comprehensive.
  871. *
  872. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  873. *
  874. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: The
  875. * <p lpvData> parameter is not a valid pointer.
  876. *
  877. * <c DIERR_ACQUIRED>: Cannot change the data format while the
  878. * device is acquired.
  879. *
  880. *
  881. *****************************************************************************/
  882. HRESULT INLINE
  883. CDIDev_SetDataFormat_IsValidDataSize(LPCDIDATAFORMAT lpdf)
  884. {
  885. HRESULT hres;
  886. if ( lpdf->dwDataSize % 4 == 0 ) {
  887. hres = S_OK;
  888. } else {
  889. RPF("IDirectInputDevice::SetDataFormat: "
  890. "dwDataSize must be a multiple of 4");
  891. hres = E_INVALIDARG;
  892. }
  893. return hres;
  894. }
  895. HRESULT INLINE
  896. CDIDev_SetDataFormat_IsValidObjectSize(LPCDIDATAFORMAT lpdf)
  897. {
  898. HRESULT hres;
  899. if ( lpdf->dwObjSize == cbX(ODF) ) {
  900. hres = S_OK;
  901. } else {
  902. RPF("IDirectInputDevice::SetDataFormat: Invalid dwObjSize");
  903. hres = E_INVALIDARG;
  904. }
  905. return hres;
  906. }
  907. STDMETHODIMP
  908. CDIDev_SetDataFormat(PV pdd, LPCDIDATAFORMAT lpdf _THAT)
  909. {
  910. HRESULT hres;
  911. EnterProcR(IDirectInputDevice::SetDataFormat, (_ "pp", pdd, lpdf));
  912. if ( SUCCEEDED(hres = hresPvT(pdd)) &&
  913. SUCCEEDED(hres = hresFullValidReadPxCb(lpdf, DIDATAFORMAT, 1)) &&
  914. SUCCEEDED(hres = hresFullValidFl(lpdf->dwFlags, DIDF_VALID, 1)) &&
  915. SUCCEEDED(hres = CDIDev_SetDataFormat_IsValidDataSize(lpdf)) &&
  916. SUCCEEDED(hres = CDIDev_SetDataFormat_IsValidObjectSize(lpdf)) &&
  917. SUCCEEDED(hres = hresFullValidReadPvCb(lpdf->rgodf,
  918. cbCxX(lpdf->dwNumObjs, ODF), 1)) ) {
  919. PDD this = _thisPv(pdd);
  920. /*
  921. * Must protect with the critical section to prevent two people
  922. * from changing the format simultaneously, or one person from
  923. * changing the data format while somebody else is reading data.
  924. */
  925. CDIDev_EnterCrit(this);
  926. #if DIRECTINPUT_VERSION >= 0x04F0
  927. if ( this->dwVersion == 0 ) {
  928. RPF("Warning: IDirectInputDevice::Initialize not called; "
  929. "assuming version 3.0");
  930. }
  931. #endif
  932. if ( !this->fAcquired ) {
  933. DIPROPDWORD dipdw;
  934. /*
  935. * Nuke the old data format stuff before proceeding.
  936. */
  937. FreePpv(&this->pdix);
  938. FreePpv(&this->rgiobj);
  939. this->cdwPOV = 0;
  940. D(this->GetState = 0);
  941. this->fPolledDataFormat = FALSE;
  942. /*
  943. * Wipe out the report IDs
  944. */
  945. dipdw.diph.dwSize = sizeof(DIPROPDWORD);
  946. dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
  947. dipdw.diph.dwObj = 0x0;
  948. dipdw.diph.dwHow = DIPH_DEVICE;
  949. dipdw.dwData = 0; // Nuke all knowledge of reportId's
  950. hres = CDIDev_RealSetProperty(this, DIPROP_ENABLEREPORTID, &dipdw.diph);
  951. if ( SUCCEEDED(hres) || hres == E_NOTIMPL )
  952. {
  953. hres = CDIDev_ParseDataFormat(this, lpdf);
  954. if ( SUCCEEDED(hres) ) {
  955. hres = CDIDev_OptimizeDataFormat(this);
  956. /*
  957. * Now set the axis mode, as a convenience.
  958. */
  959. CAssertF(DIDF_VALID == (DIDF_RELAXIS | DIDF_ABSAXIS));
  960. switch ( lpdf->dwFlags ) {
  961. case 0:
  962. hres = S_OK;
  963. goto axisdone;
  964. case DIDF_RELAXIS:
  965. dipdw.dwData = DIPROPAXISMODE_REL;
  966. break;
  967. case DIDF_ABSAXIS:
  968. dipdw.dwData = DIPROPAXISMODE_ABS;
  969. break;
  970. default:
  971. RPF("%s: Cannot combine DIDF_RELAXIS with DIDF_ABSAXIS",
  972. s_szProc);
  973. hres = E_INVALIDARG;
  974. goto axisdone;
  975. }
  976. dipdw.diph.dwSize = sizeof(DIPROPDWORD);
  977. dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
  978. dipdw.diph.dwObj = 0;
  979. dipdw.diph.dwHow = DIPH_DEVICE;
  980. hres = CDIDev_RealSetProperty(this, DIPROP_AXISMODE, &dipdw.diph);
  981. if ( SUCCEEDED(hres) ) {
  982. hres = S_OK;
  983. }
  984. }
  985. } else
  986. {
  987. SquirtSqflPtszV(sqflDf,
  988. TEXT("Could not set DIPROP_ENABLEREPORTID to 0x0"));
  989. }
  990. axisdone:;
  991. } else { /* Already acquired */
  992. hres = DIERR_ACQUIRED;
  993. }
  994. CDIDev_LeaveCrit(this);
  995. }
  996. ExitOleProcR();
  997. return hres;
  998. }
  999. /*****************************************************************************
  1000. *
  1001. * @doc EXTERNAL
  1002. *
  1003. * @method HRESULT | IDirectInputDevice | GetDeviceState |
  1004. *
  1005. * Obtains instantaneous data from the DirectInput device.
  1006. *
  1007. * Before device data can be obtained, the data format must
  1008. * be set via <mf IDirectInputDevice::SetDataFormat>, and
  1009. * the device must be acquired via
  1010. * <mf IDirectInputDevice::Acquire>.
  1011. *
  1012. * @cwrap LPDIRECTINPUTDEVICE | lpDirectInputDevice
  1013. *
  1014. * @parm DWORD | cbData |
  1015. *
  1016. * The size of the buffer pointed to by <p lpvData>, in bytes.
  1017. *
  1018. * @parm OUT LPVOID | lpvData |
  1019. *
  1020. * Points to a structure that receives the current state
  1021. * of the device.
  1022. * The format of the data is established by a prior call
  1023. * to <mf IDirectInputDevice::SetDataFormat>.
  1024. *
  1025. * @returns
  1026. *
  1027. * Returns a COM error code. The following error codes are
  1028. * intended to be illustrative and not necessarily comprehensive.
  1029. *
  1030. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  1031. *
  1032. * <c E_PENDING>: The device does not have data yet.
  1033. * Some devices (such as USB joysticks) require a delay
  1034. * between the time the device is turned on and the time
  1035. * the device begins sending data. During this "warm-up" time,
  1036. * <mf IDirectInputDevice::GetDeviceState> will return
  1037. * <c E_PENDING>. When data becomes available, the event
  1038. * notification handle will be signalled.
  1039. *
  1040. * <c DIERR_NOTACQUIRED>: The device is not acquired.
  1041. *
  1042. * <c DIERR_INPUTLOST>: Access to the device has been
  1043. * interrupted. The application should re-acquire the
  1044. * device.
  1045. *
  1046. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: The
  1047. * <p lpvData> parameter is not a valid pointer or
  1048. * the <p cbData> parameter does not match the data size
  1049. * set by a previous call to <mf IDirectInputDevice::SetDataFormat>.
  1050. *
  1051. *****************************************************************************/
  1052. extern STDMETHODIMP CDIDev_Acquire(PV pdd _THAT);
  1053. STDMETHODIMP
  1054. CDIDev_GetDeviceState(PV pdd, DWORD cbDataSize, LPVOID pvData _THAT)
  1055. {
  1056. HRESULT hres;
  1057. PDD this;
  1058. EnterProcR(IDirectInputDevice::GetDeviceState, (_ "pp", pdd, pvData));
  1059. /*
  1060. * Note that we do not validate the parameters.
  1061. * The reason is that GetDeviceState is an inner loop function,
  1062. * so it should be as fast as possible.
  1063. */
  1064. #ifdef XDEBUG
  1065. hresPvT(pdd);
  1066. hresFullValidWritePvCb(pvData, cbDataSize, 1);
  1067. #endif
  1068. this = _thisPv(pdd);
  1069. /*
  1070. * Must protect with the critical section to prevent somebody from
  1071. * unacquiring while we're reading.
  1072. */
  1073. CDIDev_EnterCrit(this);
  1074. /*
  1075. * Reacquire is not allowed until after Win98 SE, see OSR Bug # 89958
  1076. */
  1077. #if (DIRECTINPUT_VERSION > 0x061A)
  1078. if ( this->diHacks.fReacquire &&
  1079. !this->fAcquired && (this->fOnceAcquired || this->fOnceForcedUnacquired) )
  1080. {
  1081. if ( SUCCEEDED( CDIDev_Acquire(pdd THAT_) ) ) {
  1082. // 7/18/2000(a-JiTay): IA64: Use %p format specifier for 32/64-bit pointers.
  1083. RPF(" DirectInput: Auto acquired (0x%p)", pdd);
  1084. }
  1085. }
  1086. #ifdef WINNT
  1087. if( this->fUnacquiredWhenIconic && !IsIconic(this->hwnd) ) {
  1088. if ( SUCCEEDED( CDIDev_Acquire(pdd THAT_) ) ) {
  1089. this->fUnacquiredWhenIconic = 0;
  1090. RPF(" DirectInput: Auto acquired device (0x%p) after being iconic. ", pdd);
  1091. }
  1092. }
  1093. #endif
  1094. #endif
  1095. if ( this->fAcquired ) {
  1096. AssertF(this->pdix); /* Acquire shouldn't let you get this far */
  1097. AssertF(this->GetState);
  1098. AssertF(this->GetDeviceState);
  1099. AssertF(this->pdcb);
  1100. if ( this->dwDataSize == cbDataSize ) {
  1101. #ifndef DEBUG_STICKY
  1102. hres = this->GetState(this, pvData);
  1103. #else
  1104. PBYTE pbDbg;
  1105. TCHAR tszDbg[80];
  1106. hres = this->GetState(this, pvData);
  1107. for( pbDbg=(PBYTE)pvData; pbDbg<((PBYTE)pvData+cbDataSize); pbDbg++ )
  1108. {
  1109. if( *pbDbg )
  1110. {
  1111. wsprintf( tszDbg, TEXT("GotState @ 0x%02x, 0x%02x\r\n"), pbDbg-(PBYTE)pvData, *pbDbg );
  1112. OutputDebugString( tszDbg );
  1113. }
  1114. }
  1115. #endif /* DEBUG_STICKY */
  1116. if ( SUCCEEDED(hres) ) {
  1117. UINT idw;
  1118. AssertF(hres == S_OK);
  1119. /*
  1120. * Icky POV hack for apps that don't check if they have
  1121. * a POV before reading from it.
  1122. */
  1123. for ( idw = 0; idw < this->cdwPOV; idw++ ) {
  1124. DWORD UNALIGNED *pdw = pvAddPvCb(pvData, this->rgdwPOV[idw]);
  1125. *pdw = JOY_POVCENTERED;
  1126. }
  1127. hres = S_OK;
  1128. } else if ( hres == DIERR_INPUTLOST ) {
  1129. RPF("%s: Input lost", s_szProc);
  1130. CDIDev_InternalUnacquire(this);
  1131. hres = DIERR_INPUTLOST;
  1132. }
  1133. } else {
  1134. RPF("ERROR %s: arg %d: invalid value", s_szProc, 1);
  1135. hres = E_INVALIDARG;
  1136. }
  1137. } else {
  1138. hres = this->hresNotAcquired;
  1139. }
  1140. if ( FAILED(hres) ) {
  1141. ScrambleBuf(pvData, cbDataSize);
  1142. }
  1143. CDIDev_LeaveCrit(this);
  1144. ExitOleProc();
  1145. return hres;
  1146. }
  1147. #if DIRECTINPUT_VERSION > 0x0300
  1148. /*****************************************************************************
  1149. *
  1150. * @doc INTERNAL
  1151. *
  1152. * @method void | IDirectInputDevice | CookDeviceData |
  1153. *
  1154. * Cook device data that was recently obtained from the
  1155. * device buffer.
  1156. *
  1157. * Right now, only the joystick device requires cooking,
  1158. * and nobody in their right mind uses buffered joystick
  1159. * data, and the joystick has only a few objects, so we
  1160. * can afford to be slow on this.
  1161. *
  1162. * @cwrap LPDIRECTINPUTDEVICE | lpDirectInputDevice
  1163. *
  1164. * @parm UINT | cdod |
  1165. *
  1166. * Number of objects to cook.
  1167. *
  1168. * @parm LPDIDEVICEOBJECTDATA | rgdod |
  1169. *
  1170. * Array of object data to cook. The dwOfs are really
  1171. * device object indexes (relative to the device format).
  1172. * After calling the callback, we convert them into
  1173. * application data format offsets.
  1174. *
  1175. * @returns
  1176. *
  1177. * None.
  1178. *
  1179. *****************************************************************************/
  1180. void INTERNAL
  1181. CDIDev_CookDeviceData(PDD this, UINT cdod, PDOD rgdod)
  1182. {
  1183. UINT idod;
  1184. EnterProc(IDirectInputDevice::CookDeviceData,
  1185. (_ "pxp", this, cdod, rgdod));
  1186. AssertF(this->fCook);
  1187. /*
  1188. * Relative data does not need to be cooked by the callback.
  1189. */
  1190. if( ( this->pvi->fl & VIFL_RELATIVE ) == 0 )
  1191. {
  1192. this->pdcb->lpVtbl->CookDeviceData(this->pdcb, cdod, rgdod);
  1193. }
  1194. for ( idod = 0; idod < cdod; idod++ ) {
  1195. rgdod[idod].dwOfs = DICOOK_OFSFROMDFOFS(rgdod[idod].dwOfs);
  1196. }
  1197. ExitProc();
  1198. }
  1199. #endif
  1200. /*****************************************************************************
  1201. *
  1202. * @doc INTERNAL
  1203. *
  1204. * @struct SOMEDEVICEDATA |
  1205. *
  1206. * Instance data used by <mf IDirectInputDevice::GetSomeDeviceData>.
  1207. *
  1208. * @field DWORD | celtIn |
  1209. *
  1210. * Number of elements remaining in output buffer.
  1211. *
  1212. * @field PDOD | rgdod |
  1213. *
  1214. * Output buffer for data elements, or <c NULL> if
  1215. * elements should be discarded.
  1216. *
  1217. * @field DWORD | celtOut |
  1218. *
  1219. * Number of elements actually copied (so far).
  1220. *
  1221. *****************************************************************************/
  1222. typedef struct SOMEDEVICEDATA {
  1223. DWORD celtIn;
  1224. PDOD rgdod;
  1225. DWORD celtOut;
  1226. } SOMEDEVICEDATA, *PSOMEDEVICEDATA;
  1227. /*****************************************************************************
  1228. *
  1229. * @doc INTERNAL
  1230. *
  1231. * @method PDOD | IDirectInputDevice | GetSomeDeviceData |
  1232. *
  1233. * Obtains a small amount of
  1234. * buffered data from the DirectInput device.
  1235. *
  1236. * @cwrap LPDIRECTINPUTDEVICE | lpDirectInputDevice
  1237. *
  1238. * @parm PDOD | pdod |
  1239. *
  1240. * First element to copy.
  1241. *
  1242. * @parm DWORD | celt |
  1243. *
  1244. * Maximum number of elements to copy.
  1245. *
  1246. * @parm PSOMEDEVICEDATA | psdd |
  1247. *
  1248. * Structure describing the state of the ongoing
  1249. * <mf IDirectInputDevice::GetDeviceData>.
  1250. *
  1251. * @returns
  1252. *
  1253. * Returns a pointer to the first uncopied item.
  1254. *
  1255. *****************************************************************************/
  1256. PDOD INTERNAL
  1257. CDIDev_GetSomeDeviceData(PDD this, PDOD pdod, DWORD celt, PSOMEDEVICEDATA psdd)
  1258. {
  1259. EnterProc(IDirectInputDevice::GetSomeDeviceData,
  1260. (_ "ppxx", this, pdod, celt, psdd->celtIn));
  1261. /*
  1262. * Copy as many elements as fit, but not more than exist
  1263. * in the output buffer.
  1264. */
  1265. if ( celt > psdd->celtIn ) {
  1266. celt = psdd->celtIn;
  1267. }
  1268. /*
  1269. * Copy the elements (if requested) and update the state.
  1270. * Note that celt might be zero; fortunately, memcpy does
  1271. * the right thing.
  1272. */
  1273. if ( psdd->rgdod ) {
  1274. memcpy(psdd->rgdod, pdod, cbCxX(celt, DOD));
  1275. psdd->rgdod += celt;
  1276. }
  1277. psdd->celtOut += celt;
  1278. psdd->celtIn -= celt;
  1279. pdod += celt;
  1280. if ( pdod == this->pvi->pEnd ) {
  1281. pdod = this->pvi->pBuffer;
  1282. }
  1283. ExitProcX(celt);
  1284. return pdod;
  1285. }
  1286. /*****************************************************************************
  1287. *
  1288. * @doc EXTERNAL
  1289. *
  1290. * @method HRESULT | IDirectInputDevice | GetDeviceData |
  1291. *
  1292. * Obtains buffered data from the DirectInput device.
  1293. *
  1294. * DirectInput devices are, by default, unbuffered. To
  1295. * turn on buffering, you must set the buffer size
  1296. * via <mf IDirectInputDevice::SetProperty>, setting the
  1297. * <c DIPROP_BUFFERSIZE> property to the desired size
  1298. * of the input buffer.
  1299. *
  1300. * Before device data can be obtained, the data format must
  1301. * be set via <mf IDirectInputDevice::SetDataFormat>, and
  1302. * the device must be acquired via
  1303. * <mf IDirectInputDevice::Acquire>.
  1304. *
  1305. * @cwrap LPDIRECTINPUTDEVICE | lpDirectInputDevice
  1306. *
  1307. * @parm DWORD | cbObjectData |
  1308. *
  1309. * The size of a single <t DIDEVICEOBJECTDATA> structure in bytes.
  1310. *
  1311. * @parm OUT LPDIDEVICEOBJECTDATA | rgdod |
  1312. *
  1313. * Array of <t DIDEVICEOBJECTDATA> structures to receive
  1314. * the buffered data. It must consist of
  1315. * *<p pdwInOut> elements.
  1316. *
  1317. * If this parameter is <c NULL>, then the buffered data is
  1318. * not stored anywhere, but all other side-effects take place.
  1319. *
  1320. * @parm INOUT LPDWORD | pdwInOut |
  1321. *
  1322. * On entry, contains the number of elements in the array
  1323. * pointed to by <p rgdod>. On exit, contains the number
  1324. * of elements actually obtained.
  1325. *
  1326. * @parm DWORD | fl |
  1327. *
  1328. * Flags which control the manner in which data is obtained.
  1329. * It may be zero or more of the following flags:
  1330. *
  1331. * <c DIGDD_PEEK>: Do not remove the items from the buffer.
  1332. * A subsequent <mf IDirectInputDevice::GetDeviceData> will
  1333. * read the same data. Normally, data is removed from the
  1334. * buffer after it is read.
  1335. *
  1336. ;begin_internal dx4
  1337. * <c DIGDD_RESIDUAL>: Read data from the device buffer
  1338. * even if the device is not acquired. Normally, attempting
  1339. * to read device data from an unacquired device will return
  1340. * <c DIERR_NOTACQUIRED> or <c DIERR_INPUTLOST>.
  1341. ;end_internal dx4
  1342. *
  1343. * @returns
  1344. *
  1345. * <c DI_OK> = <c S_OK>: All data were retrieved
  1346. * successfully. Note that the application needs to check
  1347. * the output value of *<p pdwInOut> to determine whether
  1348. * and how much data was retrieved: The value may be zero,
  1349. * indicating that the buffer was empty.
  1350. *
  1351. * <c DI_BUFFEROVERFLOW> = <c S_FALSE>: Some data
  1352. * were retrieved successfully, but some data were lost
  1353. * because the device's buffer size was not large enough.
  1354. * The application should retrieve buffered data more frequently
  1355. * or increase the device buffer size. This status code is
  1356. * returned only on the first <mf IDirectInput::GetDeviceData>
  1357. * call after the buffer has overflowed. Note that this is
  1358. * a success status code.
  1359. *
  1360. * <c DIERR_NOTACQUIRED>: The device is not acquired.
  1361. *
  1362. * <c DIERR_INPUTLOST>: Access to the device has been
  1363. * interrupted. The application should re-acquire the
  1364. * device.
  1365. *
  1366. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: One or more
  1367. * parameters was invalid. A common cause for this is
  1368. * neglecting to set a buffer size.
  1369. *
  1370. * <c DIERR_NOTBUFFERED>: The device is not buffered.
  1371. * Set the <c DIPROP_BUFFERSIZE> property to enable buffering.
  1372. *
  1373. * @ex
  1374. *
  1375. * The following sample reads up to ten buffered data elements,
  1376. * removing them from the device buffer as they are read.
  1377. *
  1378. * |
  1379. *
  1380. * DIDEVICEOBJECTDATA rgdod[10];
  1381. * DWORD dwItems = 10;
  1382. * hres = IDirectInputDevice_GetDeviceData(
  1383. * pdid,
  1384. * sizeof(DIDEVICEOBJECTDATA),
  1385. * rgdod,
  1386. * &dwItems,
  1387. * 0);
  1388. * if (SUCCEEDED(hres)) {
  1389. * // Buffer successfully flushed.
  1390. * // dwItems = number of elements flushed
  1391. * if (hres == DI_BUFFEROVERFLOW) {
  1392. * // Buffer had overflowed.
  1393. * }
  1394. * }
  1395. *
  1396. *
  1397. *
  1398. *
  1399. * @ex
  1400. *
  1401. * If you pass <c NULL> for the <p rgdod> and request an
  1402. * infinite number of items, this has the effect of flushing
  1403. * the buffer and returning the number of items that were
  1404. * flushed.
  1405. *
  1406. * |
  1407. *
  1408. * dwItems = INFINITE;
  1409. * hres = IDirectInputDevice_GetDeviceData(
  1410. * pdid,
  1411. * sizeof(DIDEVICEOBJECTDATA),
  1412. * NULL,
  1413. * &dwItems,
  1414. * 0);
  1415. * if (SUCCEEDED(hres)) {
  1416. * // Buffer successfully flushed.
  1417. * // dwItems = number of elements flushed
  1418. * if (hres == DI_BUFFEROVERFLOW) {
  1419. * // Buffer had overflowed.
  1420. * }
  1421. * }
  1422. *
  1423. * @ex
  1424. *
  1425. * If you pass <c NULL> for the <p rgdod>, request an
  1426. * infinite number of items, and ask that the data not be
  1427. * removed from the device buffer, this has the effect of
  1428. * querying for the number of elements in the device buffer.
  1429. *
  1430. * |
  1431. *
  1432. * dwItems = INFINITE;
  1433. * hres = IDirectInputDevice_GetDeviceData(
  1434. * pdid,
  1435. * sizeof(DIDEVICEOBJECTDATA),
  1436. * NULL,
  1437. * &dwItems,
  1438. * DIGDD_PEEK);
  1439. * if (SUCCEEDED(hres)) {
  1440. * // dwItems = number of elements in buffer
  1441. * if (hres == DI_BUFFEROVERFLOW) {
  1442. * // Buffer overflow occurred; not all data
  1443. * // were successfully captured.
  1444. * }
  1445. * }
  1446. *
  1447. * @ex
  1448. *
  1449. * If you pass <c NULL> for the <p rgdod> and request zero
  1450. * items, this has the effect of querying whether buffer
  1451. * overflow has occurred.
  1452. *
  1453. * |
  1454. *
  1455. * dwItems = 0;
  1456. * hres = IDirectInputDevice_GetDeviceData(
  1457. * pdid,
  1458. * sizeof(DIDEVICEOBJECTDATA),
  1459. * NULL,
  1460. * &dwItems,
  1461. * 0);
  1462. * if (hres == DI_BUFFEROVERFLOW) {
  1463. * // Buffer overflow occurred
  1464. * }
  1465. *
  1466. *
  1467. *//**************************************************************************
  1468. *
  1469. * When reading this code, the following pictures will come in handy.
  1470. *
  1471. *
  1472. * Buffer not wrapped.
  1473. *
  1474. * pBuffer pEnd
  1475. * | |
  1476. * v v
  1477. * +----+----+----+----+----+----+----+----+----+----+----+
  1478. * | | | | | | | | | | | |
  1479. * | | | |data|data|data|data|data| | | |
  1480. * | | | | | | | | | | | |
  1481. * +----+----+----+----+----+----+----+----+----+----+----+
  1482. * ^ ^
  1483. * | |
  1484. * pTail pHead
  1485. *
  1486. *
  1487. * Buffer wrapped.
  1488. *
  1489. * pBuffer pEnd
  1490. * | |
  1491. * v v
  1492. * +----+----+----+----+----+----+----+----+----+----+----+
  1493. * | | | | | | | | | | | |
  1494. * |data|data| | | | | | |data|data|data|
  1495. * | | | | | | | | | | | |
  1496. * +----+----+----+----+----+----+----+----+----+----+----+
  1497. * ^ ^
  1498. * | |
  1499. * pHead pTail
  1500. *
  1501. *
  1502. * Boundary wrap case.
  1503. *
  1504. *
  1505. * pBuffer pEnd
  1506. * | |
  1507. * v v
  1508. * +----+----+----+----+----+----+----+----+----+----+----+
  1509. * | | | | | | | | | | | |
  1510. * | | | | | | |data|data|data|data|data|
  1511. * | | | | | | | | | | | |
  1512. * +----+----+----+----+----+----+----+----+----+----+----+
  1513. * ^ ^
  1514. * | |
  1515. * pHead pTail
  1516. *
  1517. *
  1518. * Note! At no point is pTail == pEnd or pHead == pEnd.
  1519. *
  1520. *****************************************************************************/
  1521. STDMETHODIMP
  1522. CDIDev_GetDeviceData(PV pdd, DWORD cbdod, PDOD rgdod,
  1523. LPDWORD pdwInOut, DWORD fl _THAT)
  1524. {
  1525. HRESULT hres;
  1526. PDD this;
  1527. SOMEDEVICEDATA sdd;
  1528. EnterProcR(IDirectInputDevice::GetDeviceData,
  1529. (_ "pxpxx", pdd, cbdod, rgdod,
  1530. IsBadReadPtr(pdwInOut, cbX(DWORD)) ? 0 : *pdwInOut, fl));
  1531. /*
  1532. * Note that we do not validate the parameters.
  1533. * The reason is that GetDeviceData is an inner loop function,
  1534. * so it should be as fast as possible.
  1535. *
  1536. * Note also that it is legal to get device data after the device
  1537. * has been unacquired. This lets you "turn on the faucet" for
  1538. * a short period of time, and then parse the data out later.
  1539. */
  1540. #ifdef XDEBUG
  1541. hresPvT(pdd);
  1542. if ( IsBadWritePtr(pdwInOut, cbX(*pdwInOut)) ) {
  1543. RPF("ERROR %s: arg %d: invalid value; crash soon", s_szProc, 3);
  1544. }
  1545. if ( rgdod ) {
  1546. hresFullValidWritePvCb(rgdod, cbCxX(*pdwInOut, DOD), 2);
  1547. }
  1548. #endif
  1549. this = _thisPv(pdd);
  1550. /*
  1551. * Must protect with the critical section to prevent somebody from
  1552. * acquiring/unacquiring or changing the data format or calling
  1553. * another GetDeviceData while we're reading. (We must be serialized.)
  1554. */
  1555. CDIDev_EnterCrit(this);
  1556. AssertF(CDIDev_IsConsistent(this));
  1557. if ( SUCCEEDED(hres = hresFullValidFl(fl, DIGDD_VALID, 4)) ) {
  1558. if ( cbdod == cbX(DOD) ) {
  1559. if ( this->celtBuf ) {
  1560. /*
  1561. * Don't try to read more than there possibly could be.
  1562. * This avoids overflow conditions in case celtIn is
  1563. * some absurdly huge number.
  1564. */
  1565. sdd.celtIn = *pdwInOut;
  1566. sdd.celtOut = 0;
  1567. if ( sdd.celtIn > this->celtBuf ) {
  1568. sdd.celtIn = this->celtBuf;
  1569. }
  1570. sdd.rgdod = rgdod;
  1571. /*
  1572. * For this version of DirectInput, we do not allow
  1573. * callbacks to implement their own GetDeviceData.
  1574. */
  1575. if ( this->pvi ) {
  1576. /*
  1577. * Reacquire is not allowed until after Win98 SE, see OSR Bug # 89958.
  1578. */
  1579. #if (DIRECTINPUT_VERSION > 0x061A)
  1580. if ( this->diHacks.fReacquire &&
  1581. !this->fAcquired && (this->fOnceAcquired || this->fOnceForcedUnacquired) )
  1582. {
  1583. if ( SUCCEEDED( CDIDev_Acquire(pdd THAT_) ) ) {
  1584. // 7/18/2000(a-JiTay): IA64: Use %p format specifier for 32/64-bit pointers.
  1585. RPF(" DirectInput: Auto acquired device (0x%p)", pdd);
  1586. }
  1587. }
  1588. #ifdef WINNT
  1589. if( this->fUnacquiredWhenIconic && !IsIconic(this->hwnd) ) {
  1590. if ( SUCCEEDED( CDIDev_Acquire(pdd THAT_) ) ) {
  1591. this->fUnacquiredWhenIconic = 0;
  1592. RPF(" DirectInput: Auto acquired device (0x%p) after being iconic. ", pdd);
  1593. }
  1594. }
  1595. #endif
  1596. #endif
  1597. if ( (this->fAcquired && (this->pvi->fl & VIFL_ACQUIRED)) ||
  1598. (fl & DIGDD_RESIDUAL) ) {
  1599. LPDIDEVICEOBJECTDATA pdod, pdodHead;
  1600. DWORD celt;
  1601. /*
  1602. * Snapshot the value of pdodHead, because it can
  1603. * change asynchronously. The other fields won't
  1604. * change unless we ask for them to be changed.
  1605. */
  1606. pdodHead = this->pvi->pHead;
  1607. /*
  1608. * Throughout, pdod points to the first unprocessed
  1609. * element.
  1610. */
  1611. pdod = this->pvi->pTail;
  1612. /*
  1613. * If we are wrapped, handle the initial run.
  1614. */
  1615. if ( pdodHead < this->pvi->pTail ) {
  1616. celt = (DWORD)(this->pvi->pEnd - this->pvi->pTail);
  1617. AssertF(celt);
  1618. pdod = CDIDev_GetSomeDeviceData(this, pdod, celt, &sdd);
  1619. }
  1620. /*
  1621. * Now handle the glob from pdod to pdodHead.
  1622. * Remember, pvi->pdodHead may have changed
  1623. * behind our back; use the cached value to
  1624. * ensure consistency. (If we miss data,
  1625. * it'll show up later.)
  1626. */
  1627. AssertF(fLimpFF(sdd.celtIn, pdodHead >= pdod));
  1628. celt = (DWORD)(pdodHead - pdod);
  1629. if ( celt ) {
  1630. pdod = CDIDev_GetSomeDeviceData(this, pdod, celt, &sdd);
  1631. }
  1632. *pdwInOut = sdd.celtOut;
  1633. if ( !(fl & DIGDD_PEEK) ) {
  1634. this->pvi->pTail = pdod;
  1635. }
  1636. #if DIRECTINPUT_VERSION > 0x0300
  1637. if ( rgdod && sdd.celtOut && this->fCook ) {
  1638. CDIDev_CookDeviceData(this, sdd.celtOut, rgdod);
  1639. }
  1640. #endif
  1641. CAssertF(S_OK == 0);
  1642. CAssertF(DI_BUFFEROVERFLOW == 1);
  1643. hres = (HRESULT)(UINT_PTR)pvExchangePpvPv(&this->pvi->fOverflow, 0);
  1644. #ifdef DEBUG_STICKY
  1645. if( hres == 1 )
  1646. {
  1647. OutputDebugString( TEXT( "Device buffer overflowed\r\n" ) );
  1648. }
  1649. if( sdd.celtOut )
  1650. {
  1651. PDOD pdoddbg;
  1652. TCHAR tszDbg[80];
  1653. wsprintf( tszDbg, TEXT("GotData %d elements: "), sdd.celtOut );
  1654. OutputDebugString( tszDbg );
  1655. for( pdoddbg=rgdod; pdoddbg<&rgdod[sdd.celtOut]; pdoddbg++ )
  1656. {
  1657. wsprintf( tszDbg, TEXT("0x%02x:x0x%08x "), pdoddbg->dwOfs, pdoddbg->dwData );
  1658. OutputDebugString( tszDbg );
  1659. }
  1660. OutputDebugString( TEXT("\r\n") );
  1661. }
  1662. #endif /* DEBUG_STICKY */
  1663. } else if (this->fAcquired && !(this->pvi->fl & VIFL_ACQUIRED)) {
  1664. RPF("ERROR %s - %s", s_szProc, "input lost");
  1665. hres = DIERR_INPUTLOST;
  1666. CDIDev_InternalUnacquire(this);
  1667. } else {
  1668. RPF("ERROR %s: %s", s_szProc,
  1669. this->hresNotAcquired == DIERR_NOTACQUIRED
  1670. ? "Not acquired" : "Input lost");
  1671. hres = this->hresNotAcquired;
  1672. }
  1673. } else { /* Don't support device-side GetData yet */
  1674. hres = E_NOTIMPL;
  1675. }
  1676. } else { /* Device is not buffered */
  1677. #ifdef XDEBUG
  1678. if ( !this->fNotifiedNotBuffered ) {
  1679. this->fNotifiedNotBuffered = 1;
  1680. RPF("ERROR %s: arg %d: device is not buffered", s_szProc, 0);
  1681. }
  1682. #endif
  1683. #if DIRECTINPUT_VERSION > 0x0300
  1684. hres = DIERR_NOTBUFFERED;
  1685. #else
  1686. hres = E_INVALIDARG;
  1687. #endif
  1688. }
  1689. } else {
  1690. RPF("ERROR %s: arg %d: invalid value", s_szProc, 1);
  1691. }
  1692. }
  1693. CDIDev_LeaveCrit(this);
  1694. return hres;
  1695. }
  1696. #ifdef IDirectInputDevice2Vtbl
  1697. /*****************************************************************************
  1698. *
  1699. * @doc EXTERNAL
  1700. *
  1701. * @method HRESULT | IDirectInputDevice2 | Poll |
  1702. *
  1703. * Retrieves data from polled objects on a DirectInput device.
  1704. * If the device does not require polling, then calling this
  1705. * method has no effect. If a device that requires polling
  1706. * is not polled periodically, no new data will be received
  1707. * from the device.
  1708. *
  1709. * Before a device data can be polled, the data format must
  1710. * be set via <mf IDirectInputDevice::SetDataFormat>, and
  1711. * the device must be acquired via
  1712. * <mf IDirectInputDevice::Acquire>.
  1713. *
  1714. * @cwrap LPDIRECTINPUTDEVICE | lpDirectInputDevice
  1715. *
  1716. * @returns
  1717. *
  1718. * Returns a COM error code. The following error codes are
  1719. * intended to be illustrative and not necessarily comprehensive.
  1720. *
  1721. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  1722. *
  1723. * <c DI_NOEFFECT> = <c S_FALSE>: The device does not require
  1724. * polling.
  1725. *
  1726. * <c DIERR_INPUTLOST>: Access to the device has been
  1727. * interrupted. The application should re-acquire the
  1728. * device.
  1729. *
  1730. * <c DIERR_NOTACQUIRED>: The device is not acquired.
  1731. *
  1732. *****************************************************************************/
  1733. STDMETHODIMP
  1734. CDIDev_Poll(PV pdd _THAT)
  1735. {
  1736. HRESULT hres;
  1737. PDD this;
  1738. EnterProcR(IDirectInputDevice::Poll, (_ "p", pdd));
  1739. /*
  1740. * Note that we do not validate the parameters.
  1741. * The reason is that Poll is an inner loop function,
  1742. * so it should be as fast as possible.
  1743. */
  1744. #ifdef XDEBUG
  1745. hresPvT(pdd);
  1746. #endif
  1747. this = _thisPv(pdd);
  1748. /*
  1749. * Fast out: If the device doesn't require polling,
  1750. * then don't bother with the critical section or other validation.
  1751. */
  1752. if ( this->fPolledDataFormat ) {
  1753. /*
  1754. * Must protect with the critical section to prevent somebody from
  1755. * unacquiring while we're polling.
  1756. */
  1757. CDIDev_EnterCrit(this);
  1758. if ( this->fAcquired ) {
  1759. hres = this->pdcb->lpVtbl->Poll(this->pdcb);
  1760. } else {
  1761. hres = this->hresNotAcquired;
  1762. }
  1763. CDIDev_LeaveCrit(this);
  1764. } else {
  1765. if ( this->fAcquired ) {
  1766. if( this->dwVersion < 0x05B2 ) {
  1767. hres = S_OK;
  1768. } else {
  1769. hres = S_FALSE;
  1770. }
  1771. } else {
  1772. hres = this->hresNotAcquired;
  1773. }
  1774. }
  1775. ExitOleProc();
  1776. return hres;
  1777. }
  1778. /*****************************************************************************
  1779. *
  1780. * @doc EXTERNAL
  1781. *
  1782. * @method HRESULT | IDirectInputDevice2 | SendDeviceData |
  1783. *
  1784. * Sends data to the device.
  1785. *
  1786. * Before device data can be sent to a device,
  1787. * the device must be acquired via
  1788. * <mf IDirectInputDevice::Acquire>.
  1789. *
  1790. * Note that no guarantees
  1791. * are made on the order in which the individual data
  1792. * elements are sent. However, data sent by
  1793. * successive calls to
  1794. * <mf IDirectInputDevice2::SendDeviceData>
  1795. * will not be interleaved.
  1796. * Furthermore, if multiple pieces of
  1797. * data are sent to the same object, it is unspecified
  1798. * which actual piece of data is sent.
  1799. *
  1800. * Consider, for example, a device which can be sent
  1801. * data in packets, each packet describing two pieces
  1802. * of information, call them A and B. Suppose the
  1803. * application attempts to send three data elements,
  1804. * "B = 2", "A = 1", and "B = 0".
  1805. *
  1806. * The actual device will be sent a single packet.
  1807. * The "A" field of the packet will contain the value 1,
  1808. * and the "B" field of the packet will be either 2 or 0.
  1809. *
  1810. * If the application wishes the data to be sent to the
  1811. * device exactly as specified, then three calls to
  1812. * <mf IDirectInputDevice2::SendDeviceData> should be
  1813. * performed, each call sending one data element.
  1814. *
  1815. * In response to the first call,
  1816. * the device will be sent a packet where the "A" field
  1817. * is blank and the "B" field contains the value 2.
  1818. *
  1819. * In response to the second call,
  1820. * the device will be sent a packet where the "A" field
  1821. * contains the value 1, and the "B" field is blank.
  1822. *
  1823. * Finally, in response to the third call,
  1824. * the device will be sent a packet where the "A" field
  1825. * is blank and the "B" field contains the value 0.
  1826. *
  1827. *
  1828. *
  1829. * @cwrap LPDIRECTINPUTDEVICE | lpDirectInputDevice
  1830. *
  1831. * @parm DWORD | cbObjectData |
  1832. *
  1833. * The size of a single <t DIDEVICEOBJECTDATA> structure in bytes.
  1834. *
  1835. * @parm IN LPCDIDEVICEOBJECTDATA | rgdod |
  1836. *
  1837. * Array of <t DIDEVICEOBJECTDATA> structures containing
  1838. * the data to send to the device. It must consist of
  1839. * *<p pdwInOut> elements.
  1840. *
  1841. * <y Note>: The <e DIDEVICEOBJECTDATA.dwOfs> field of
  1842. * the <t DIDEVICEOBJECTDATA> structure must contain the
  1843. * device object identifier (as obtained from the
  1844. * <e DIDEVICEOBJECTINSTANCE.dwType> field of the
  1845. * <t DIDEVICEOBJECTINSTANCE> sturcture) for the device
  1846. * object at which the data is directed.
  1847. *
  1848. * Furthermore, the <e DIDEVICEOBJECTDATA.dwTimeStamp>
  1849. * and <e DIDEVICEOBJECTDATA.dwSequence> fields are
  1850. * reserved for future use and must be zero.
  1851. *
  1852. * @parm INOUT LPDWORD | pdwInOut |
  1853. *
  1854. * On entry, contains the number of elements in the array
  1855. * pointed to by <p rgdod>. On exit, contains the number
  1856. * of elements actually sent to the device.
  1857. *
  1858. * @parm DWORD | fl |
  1859. *
  1860. * Flags which control the manner in which data is sent.
  1861. * It may consist of zero or more of the following flags:
  1862. *
  1863. * <c DISDD_CONTINUE>: If this flag is set, then
  1864. * the device data sent will be overlaid upon the previously
  1865. * sent device data. Otherwise, the device data sent
  1866. * will start from scratch.
  1867. *
  1868. * For example, suppose a device supports two button outputs,
  1869. * call them A and B.
  1870. * If an application first calls
  1871. * <mf IDirectInputDevice2::SendDeviceData> passing
  1872. * "button A pressed", then
  1873. * a packet of the form "A pressed, B not pressed" will be
  1874. * sent to the device.
  1875. * If an application then calls
  1876. * <mf IDirectInputDevice2::SendDeviceData> passing
  1877. * "button B pressed" and the <c DISDD_CONTINUE> flag, then
  1878. * a packet of the form "A pressed, B pressed" will be
  1879. * sent to the device.
  1880. * However, if the application had not passed the
  1881. * <c DISDD_CONTINUE> flag, then the packet sent to the device
  1882. * would have been "A not pressed, B pressed".
  1883. *
  1884. * @returns
  1885. *
  1886. * Returns a COM error code. The following error codes are
  1887. * intended to be illustrative and not necessarily comprehensive.
  1888. *
  1889. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  1890. *
  1891. * <c DIERR_INPUTLOST>: Access to the device has been
  1892. * interrupted. The application should re-acquire the
  1893. * device.
  1894. *
  1895. * <c DIERR_NOTACQUIRED>: The device is not acquired.
  1896. *
  1897. *****************************************************************************/
  1898. STDMETHODIMP
  1899. CDIDev_SendDeviceData(PV pdd, DWORD cbdod, PCDOD rgdod,
  1900. LPDWORD pdwInOut, DWORD fl _THAT)
  1901. {
  1902. HRESULT hres;
  1903. PDD this;
  1904. EnterProcR(IDirectInputDevice::SendDeviceData,
  1905. (_ "pxpxx", pdd, cbdod, rgdod,
  1906. IsBadReadPtr(pdwInOut, cbX(DWORD)) ? 0 : *pdwInOut, fl));
  1907. /*
  1908. * Note that we do not validate the parameters.
  1909. * The reason is that SendDeviceData is an inner loop function,
  1910. * so it should be as fast as possible.
  1911. */
  1912. #ifdef XDEBUG
  1913. hresPvT(pdd);
  1914. if ( IsBadWritePtr(pdwInOut, cbX(*pdwInOut)) ) {
  1915. RPF("ERROR %s: arg %d: invalid value; crash soon", s_szProc, 3);
  1916. }
  1917. hresFullValidReadPvCb(rgdod, cbCxX(*pdwInOut, DOD), 2);
  1918. #endif
  1919. this = _thisPv(pdd);
  1920. /*
  1921. * Must protect with the critical section to prevent somebody from
  1922. * unacquiring while we're sending data.
  1923. */
  1924. CDIDev_EnterCrit(this);
  1925. if ( SUCCEEDED(hres = hresFullValidFl(fl, DISDD_VALID, 4)) ) {
  1926. if ( cbdod == cbX(DOD) ) {
  1927. #ifdef XDEBUG
  1928. UINT iod;
  1929. for ( iod = 0; iod < *pdwInOut; iod++ ) {
  1930. if ( rgdod[iod].dwTimeStamp ) {
  1931. RPF("%s: ERROR: dwTimeStamp must be zero", s_szProc);
  1932. }
  1933. if ( rgdod[iod].dwSequence ) {
  1934. RPF("%s: ERROR: dwSequence must be zero", s_szProc);
  1935. }
  1936. }
  1937. #endif
  1938. if ( this->fAcquired ) {
  1939. UINT iod;
  1940. for ( iod=0; iod < *pdwInOut; iod++ ) {
  1941. int iobj = CDIDev_OffsetToIobj(this, rgdod[iod].dwOfs);
  1942. LPDWORD pdw = (LPDWORD)&rgdod[iod].dwOfs;
  1943. *pdw = this->df.rgodf[iobj].dwType;
  1944. }
  1945. hres = this->pdcb->lpVtbl->SendDeviceData(this->pdcb,
  1946. rgdod, pdwInOut, fl);
  1947. } else {
  1948. hres = this->hresNotAcquired;
  1949. }
  1950. } else {
  1951. RPF("ERROR %s: arg %d: invalid value", s_szProc, 1);
  1952. }
  1953. }
  1954. CDIDev_LeaveCrit(this);
  1955. ExitOleProc();
  1956. return hres;
  1957. }
  1958. #endif
  1959. /*****************************************************************************
  1960. *
  1961. * @doc INTERNAL
  1962. *
  1963. * @func BOOL | CDIDev_CheckId |
  1964. *
  1965. * Verify that the item has the appropriate type.
  1966. *
  1967. * @parm DWORD | dwId |
  1968. *
  1969. * ID to locate.
  1970. *
  1971. * @parm UINT | fl |
  1972. *
  1973. * Bitmask of flags for things to validate.
  1974. *
  1975. * The <c DEVCO_TYPEMASK> fields describe what type
  1976. * of object we should be locating.
  1977. *
  1978. * The <c DEVCO_ATTRMASK> fields describe the attribute
  1979. * bits that are required.
  1980. *
  1981. *****************************************************************************/
  1982. BOOL INLINE
  1983. CDIDev_CheckId(DWORD dwId, DWORD fl)
  1984. {
  1985. CAssertF(DIDFT_ATTRMASK == DEVCO_ATTRMASK);
  1986. return(dwId & fl & DEVCO_TYPEMASK) &&
  1987. fHasAllBitsFlFl(dwId, fl & DIDFT_ATTRMASK);
  1988. }
  1989. /*****************************************************************************
  1990. *
  1991. * @doc INTERNAL
  1992. *
  1993. * @method int | CDIDev | IdToIobj |
  1994. *
  1995. * Locate an item which matches the specified ID.
  1996. *
  1997. * @cwrap PDD | this
  1998. *
  1999. * @parm DWORD | dwId |
  2000. *
  2001. * ID to locate.
  2002. *
  2003. * @returns
  2004. *
  2005. * Returns the index of the object found, or -1 on error.
  2006. *
  2007. *****************************************************************************/
  2008. int INTERNAL
  2009. CDIDev_IdToIobj(PDD this, DWORD dwId)
  2010. {
  2011. int iobj;
  2012. /* Someday: Perf: Should have xlat table */
  2013. for ( iobj = this->df.dwNumObjs; --iobj >= 0; ) {
  2014. PODF podf = &this->df.rgodf[iobj];
  2015. if ( DIDFT_FINDMATCH(podf->dwType, dwId) ) {
  2016. goto done;
  2017. }
  2018. }
  2019. iobj = -1;
  2020. done:;
  2021. return iobj;
  2022. }
  2023. #if 0
  2024. /*****************************************************************************
  2025. *
  2026. * @doc INTERNAL
  2027. *
  2028. * @method HRESULT | CDIDev | IdToId |
  2029. *
  2030. * Convert a single <t DWORD> from an ID to an ID.
  2031. *
  2032. * This is clearly a very simple operation.
  2033. *
  2034. * It's all validation.
  2035. *
  2036. * @cwrap PDD | this
  2037. *
  2038. * @parm LPDWORD | pdw |
  2039. *
  2040. * Single item to convert.
  2041. *
  2042. * @parm UINT | fl |
  2043. *
  2044. * Bitmask of flags that govern the conversion.
  2045. * The function should look only at
  2046. * <c DEVCO_AXIS> or <c DEVCO_BUTTON>.
  2047. *
  2048. *****************************************************************************/
  2049. HRESULT INTERNAL
  2050. CDIDev_IdToId(PDD this, LPDWORD pdw, UINT fl)
  2051. {
  2052. HRESULT hres;
  2053. int iobj;
  2054. iobj = CDIDev_FindId(this, *pdw, fl);
  2055. if ( iobj >= 0 ) {
  2056. *pdw = this->df.rgodf[iobj].dwType;
  2057. hres = S_OK;
  2058. } else {
  2059. hres = E_INVALIDARG;
  2060. }
  2061. return hres;
  2062. }
  2063. #endif
  2064. /*****************************************************************************
  2065. *
  2066. * @doc INTERNAL
  2067. *
  2068. * @method int | CDIDev | OffsetToIobj |
  2069. *
  2070. * Convert a single <t DWORD> from an offset to an object index.
  2071. *
  2072. * @cwrap PDD | this
  2073. *
  2074. * @parm DWORD | dwOfs |
  2075. *
  2076. * Offset to convert.
  2077. *
  2078. *****************************************************************************/
  2079. int INTERNAL
  2080. CDIDev_OffsetToIobj(PDD this, DWORD dwOfs)
  2081. {
  2082. int iobj;
  2083. AssertF(this->pdix);
  2084. AssertF(this->rgiobj);
  2085. if ( dwOfs < this->dwDataSize ) {
  2086. iobj = this->rgiobj[dwOfs];
  2087. if ( iobj >= 0 ) {
  2088. AssertF(this->pdix[iobj].dwOfs == dwOfs);
  2089. } else {
  2090. AssertF(iobj == -1);
  2091. }
  2092. } else {
  2093. iobj = -1;
  2094. }
  2095. return iobj;
  2096. }
  2097. /*****************************************************************************
  2098. *
  2099. * @doc INTERNAL
  2100. *
  2101. * @method int | CDIDev | IobjToId |
  2102. *
  2103. * Convert an object index to an ID.
  2104. *
  2105. * @cwrap PDD | this
  2106. *
  2107. * @parm int | iobj |
  2108. *
  2109. * Single item to convert.
  2110. *
  2111. *****************************************************************************/
  2112. DWORD INLINE
  2113. CDIDev_IobjToId(PDD this, int iobj)
  2114. {
  2115. AssertF((DWORD)iobj < this->df.dwNumObjs);
  2116. return this->df.rgodf[iobj].dwType;
  2117. }
  2118. /*****************************************************************************
  2119. *
  2120. * @doc INTERNAL
  2121. *
  2122. * @method int | CDIDev | IobjToOffset |
  2123. *
  2124. * Convert an object index to an offset.
  2125. *
  2126. * @cwrap PDD | this
  2127. *
  2128. * @parm int | iobj |
  2129. *
  2130. * Single item to convert.
  2131. *
  2132. *****************************************************************************/
  2133. DWORD INLINE
  2134. CDIDev_IobjToOffset(PDD this, int iobj)
  2135. {
  2136. AssertF((DWORD)iobj < this->df.dwNumObjs);
  2137. AssertF(this->pdix);
  2138. return this->pdix[iobj].dwOfs;
  2139. }
  2140. /*****************************************************************************
  2141. *
  2142. * @doc INTERNAL
  2143. *
  2144. * @method HRESULT | CDIDev | ConvertObjects |
  2145. *
  2146. * Convert between the ways of talking about device gizmos.
  2147. *
  2148. * Since this is used only by the force feedback subsystem,
  2149. * we also barf if the device found does not support
  2150. * force feedback.
  2151. *
  2152. * @cwrap PDD | this
  2153. *
  2154. * @parm UINT | cdw |
  2155. *
  2156. * Number of elements to convert (in-place).
  2157. *
  2158. * @parm LPDWORD | rgdw |
  2159. *
  2160. * Array of elements to convert.
  2161. *
  2162. * @parm UINT | fl |
  2163. *
  2164. * Flags that describe how to do the conversion.
  2165. *
  2166. * <c DEVCO_AXIS> or <c DEVCO_BUTTON> indicate whether
  2167. * the item being converted is an axis or button.
  2168. *
  2169. * <c DEVCO_FROM*> specifies what the existing value is.
  2170. *
  2171. * <c DEVCO_TO*> specifies what the new values should be.
  2172. *
  2173. *****************************************************************************/
  2174. STDMETHODIMP
  2175. CDIDev_ConvertObjects(PDD this, UINT cdw, LPDWORD rgdw, UINT fl)
  2176. {
  2177. HRESULT hres;
  2178. /*
  2179. * Don't let somebody change the data format while we're
  2180. * looking at it.
  2181. */
  2182. CDIDev_EnterCrit(this);
  2183. AssertF((fl & ~DEVCO_VALID) == 0);
  2184. if ( fLimpFF(fl & (DEVCO_FROMOFFSET | DEVCO_TOOFFSET),
  2185. this->pdix && this->rgiobj) ) {
  2186. UINT idw;
  2187. for ( idw = 0; idw < cdw; idw++ ) {
  2188. /*
  2189. * Convert from its source to an object index,
  2190. * validate the object index, then convert to
  2191. * the target.
  2192. */
  2193. int iobj;
  2194. switch ( fl & DEVCO_FROMMASK ) {
  2195. default:
  2196. AssertF(0); /* Huh? */
  2197. case DEVCO_FROMID:
  2198. iobj = CDIDev_IdToIobj(this, rgdw[idw]);
  2199. break;
  2200. case DEVCO_FROMOFFSET:
  2201. iobj = CDIDev_OffsetToIobj(this, rgdw[idw]);
  2202. break;
  2203. }
  2204. if ( iobj < 0 ) {
  2205. hres = E_INVALIDARG; /* Invalid object */
  2206. goto done;
  2207. }
  2208. AssertF((DWORD)iobj < this->df.dwNumObjs);
  2209. if ( !CDIDev_CheckId(this->df.rgodf[iobj].dwType, fl) ) {
  2210. hres = E_INVALIDARG; /* Bad attributes */
  2211. goto done;
  2212. }
  2213. switch ( fl & DEVCO_TOMASK ) {
  2214. default:
  2215. AssertF(0); /* Huh? */
  2216. case DEVCO_TOID:
  2217. rgdw[idw] = CDIDev_IobjToId(this, iobj);
  2218. break;
  2219. case DEVCO_TOOFFSET:
  2220. rgdw[idw] = CDIDev_IobjToOffset(this, iobj);
  2221. break;
  2222. }
  2223. }
  2224. hres = S_OK;
  2225. done:;
  2226. } else {
  2227. RPF("ERROR: Must have a data format to use offsets");
  2228. hres = E_INVALIDARG;
  2229. }
  2230. CDIDev_LeaveCrit(this);
  2231. return hres;
  2232. }