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.

6338 lines
214 KiB

  1. /*****************************************************************************
  2. *
  3. * DIDevDf.c
  4. *
  5. * Copyright (c) 1996 - 2000 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. #undef sqfl
  16. #define sqfl sqflDf
  17. int INTERNAL
  18. CDIDev_OffsetToIobj(PDD this, DWORD dwOfs);
  19. /*****************************************************************************
  20. *
  21. * @doc INTERNAL
  22. *
  23. * @func HRESULT | CDIDev_GetAbsDeviceState |
  24. *
  25. * Get the absolute device state.
  26. *
  27. * @parm OUT LPVOID | pvData |
  28. *
  29. * Application-provided output buffer.
  30. *
  31. *****************************************************************************/
  32. STDMETHODIMP
  33. CDIDev_GetAbsDeviceState(PDD this, LPVOID pvData)
  34. {
  35. return this->pdcb->lpVtbl->GetDeviceState(this->pdcb, pvData);
  36. }
  37. /*****************************************************************************
  38. *
  39. * @doc INTERNAL
  40. *
  41. * @func HRESULT | CDIDev_GetRelDeviceState |
  42. *
  43. * Get the relative device state.
  44. *
  45. * @parm OUT LPVOID | pvData |
  46. *
  47. * Application-provided output buffer.
  48. *
  49. *****************************************************************************/
  50. STDMETHODIMP
  51. CDIDev_GetRelDeviceState(PDD this, LPVOID pvData)
  52. {
  53. HRESULT hres;
  54. hres = this->pdcb->lpVtbl->GetDeviceState(this->pdcb, pvData);
  55. if ( SUCCEEDED(hres) ) {
  56. UINT iaxis;
  57. AssertF(fLimpFF(this->cAxes, this->pvLastBuffer && this->rgdwAxesOfs));
  58. /*
  59. * For each axis, replace the app's buffer with the delta,
  60. * and save the old value.
  61. */
  62. for ( iaxis = 0; iaxis < this->cAxes; iaxis++ ) {
  63. LONG UNALIGNED *plApp = pvAddPvCb(pvData, this->rgdwAxesOfs[iaxis]);
  64. LONG UNALIGNED *plLast = pvAddPvCb(this->pvLastBuffer,
  65. this->rgdwAxesOfs[iaxis]);
  66. LONG lNew = *plApp;
  67. *plApp -= *plLast;
  68. *plLast = lNew;
  69. }
  70. hres = S_OK;
  71. }
  72. return hres;
  73. }
  74. /*****************************************************************************
  75. *
  76. * @doc INTERNAL
  77. *
  78. * @func HRESULT | CDIDev_GetDeviceStateSlow |
  79. *
  80. * Obtains data from the DirectInput device the slow way.
  81. *
  82. * Read the data into the private buffer, then copy it
  83. * bit by bit into the application's buffer.
  84. *
  85. * @parm OUT LPVOID | lpvData |
  86. *
  87. * Application-provided output buffer.
  88. *
  89. *****************************************************************************/
  90. STDMETHODIMP
  91. CDIDev_GetDeviceStateSlow(PDD this, LPVOID pvData)
  92. {
  93. HRESULT hres;
  94. EnterProcR(IDirectInputDevice8::GetDeviceStateSlow, (_ "pp", this, pvData));
  95. AssertF(this->diopt == dioptNone);
  96. AssertF(this->pvBuffer);
  97. AssertF(this->pdcb);
  98. hres = this->GetDeviceState(this, this->pvBuffer);
  99. if ( SUCCEEDED(hres) ) {
  100. int iobj;
  101. ZeroMemory(pvData, this->dwDataSize);
  102. for ( iobj = this->df.dwNumObjs; --iobj >= 0; ) {
  103. if ( this->pdix[iobj].dwOfs != 0xFFFFFFFF ) { /* Data was requested */
  104. DWORD UNALIGNED *pdwOut = pvAddPvCb(pvData, this->pdix[iobj].dwOfs);
  105. DWORD UNALIGNED *pdwIn = pvAddPvCb(this->pvBuffer, this->df.rgodf[iobj].dwOfs);
  106. if ( this->df.rgodf[iobj].dwType & DIDFT_DWORDOBJS ) {
  107. *pdwOut = *pdwIn;
  108. } else {
  109. *(LPBYTE)pdwOut = *(LPBYTE)pdwIn;
  110. }
  111. }
  112. }
  113. }
  114. ExitOleProc();
  115. return hres;
  116. }
  117. /*****************************************************************************
  118. *
  119. * @doc INTERNAL
  120. *
  121. * @func HRESULT | CDIDev_GetDeviceStateMatched |
  122. *
  123. * Obtains data from the DirectInput device in the case
  124. * where the data formats are matched.
  125. *
  126. * Read the data into the private buffer, then block copy it
  127. * into the application's buffer.
  128. *
  129. * @parm OUT LPVOID | lpvData |
  130. *
  131. * Application-provided output buffer.
  132. *
  133. *****************************************************************************/
  134. STDMETHODIMP
  135. CDIDev_GetDeviceStateMatched(PDD this, LPVOID pvData)
  136. {
  137. HRESULT hres;
  138. EnterProcR(IDirectInputDevice8::GetDeviceStateMatched, (_ "pp", this, pvData));
  139. AssertF(this->diopt == dioptMatch);
  140. AssertF(this->pvBuffer);
  141. AssertF(this->pdcb);
  142. hres = this->GetDeviceState(this, this->pvBuffer);
  143. if ( SUCCEEDED(hres) ) {
  144. /*
  145. * To keep keyboard clients happy: Zero out the fore and aft.
  146. * No need to optimize the perfect match case, because that
  147. * gets a different optimization level.
  148. */
  149. ZeroMemory(pvData, this->dwDataSize);
  150. memcpy(pvAddPvCb(pvData, this->ibDelta + this->ibMin),
  151. pvAddPvCb(this->pvBuffer, this->ibMin), this->cbMatch);
  152. }
  153. ExitOleProc();
  154. return hres;
  155. }
  156. /*****************************************************************************
  157. *
  158. * @doc INTERNAL
  159. *
  160. * @func HRESULT | CDIDev_GetDeviceStateDirect |
  161. *
  162. * Obtains data from the DirectInput device in the case
  163. * where we can read the data directly into the client buffer.
  164. *
  165. * @parm OUT LPVOID | lpvData |
  166. *
  167. * Application-provided output buffer.
  168. *
  169. *****************************************************************************/
  170. STDMETHODIMP
  171. CDIDev_GetDeviceStateDirect(PDD this, LPVOID pvData)
  172. {
  173. HRESULT hres;
  174. EnterProcR(IDirectInputDevice8::GetDeviceStateDirect, (_ "pp", this, pvData));
  175. AssertF(this->diopt == dioptDirect);
  176. AssertF(!this->pvBuffer);
  177. AssertF(this->pdcb);
  178. /*
  179. * To keep keyboard clients happy: Zero out the fore and aft.
  180. */
  181. ZeroBuf(pvData, this->dwDataSize);
  182. hres = this->GetDeviceState(this, pvAddPvCb(pvData, this->ibDelta));
  183. ExitOleProc();
  184. return hres;
  185. }
  186. /*****************************************************************************
  187. *
  188. * @doc INTERNAL
  189. *
  190. * @func HRESULT | CDIDev_GetDeviceStateEqual |
  191. *
  192. * Obtains data from the DirectInput device in the case
  193. * where the two data formats are completely identical.
  194. *
  195. * @parm OUT LPVOID | lpvData |
  196. *
  197. * Application-provided output buffer.
  198. *
  199. *****************************************************************************/
  200. STDMETHODIMP
  201. CDIDev_GetDeviceStateEqual(PDD this, LPVOID pvData)
  202. {
  203. HRESULT hres;
  204. EnterProcR(IEqualInputDevice::GetDeviceStateEqual, (_ "pp", this, pvData));
  205. AssertF(this->diopt == dioptEqual);
  206. AssertF(this->ibDelta == 0);
  207. AssertF(this->dwDataSize == this->df.dwDataSize);
  208. AssertF(!this->pvBuffer);
  209. AssertF(this->pdcb);
  210. /*
  211. * Note that this->ibMin is not necessarily zero if the device
  212. * data format doesn't begin at zero (which keyboards don't).
  213. */
  214. hres = this->GetDeviceState(this, pvData);
  215. ExitOleProc();
  216. return hres;
  217. }
  218. /*****************************************************************************
  219. *
  220. * @doc INTERNAL
  221. *
  222. * @method BOOL | CDIDev | IsMatchingGUID |
  223. *
  224. * Helper function that checks if a <t GUID> counts as
  225. * a match when parsing the data format.
  226. *
  227. * @parm PCGUID | pguidSrc |
  228. *
  229. * The <t GUID> to check.
  230. *
  231. * @parm PCGUID | pguidDst |
  232. *
  233. * The <t GUID> it should match.
  234. *
  235. * @returns
  236. *
  237. * Nonzero if this counts as a success.
  238. *
  239. *****************************************************************************/
  240. #pragma BEGIN_CONST_DATA
  241. GUID GUID_Null; /* A zero-filled guid */
  242. #pragma END_CONST_DATA
  243. BOOL INLINE
  244. CDIDev_IsMatchingGUID(PDD this, PCGUID pguidSrc, PCGUID pguidDst)
  245. {
  246. UNREFERENCED_PARAMETER( this );
  247. return IsEqualGUID(pguidSrc, &GUID_Null) ||
  248. IsEqualGUID(pguidSrc, pguidDst);
  249. }
  250. /*****************************************************************************
  251. *
  252. * @doc INTERNAL
  253. *
  254. * @method BOOL | CDIDev | IsMatchingUsage |
  255. *
  256. * Helper function that checks if a <f DIMAKEUSAGEDWORD>
  257. * counts as a match when parsing the data format.
  258. *
  259. * @parm DWORD | dwUsage |
  260. *
  261. * The <f DIMAKEUSAGEDWORD> to check.
  262. *
  263. * @parm int | iobj |
  264. *
  265. * The index of hte object to check for a match.
  266. *
  267. * @returns
  268. *
  269. * Nonzero if this counts as a success.
  270. *
  271. *****************************************************************************/
  272. BOOL INLINE
  273. CDIDev_IsMatchingUsage(PDD this, DWORD dwUsage, int iobj)
  274. {
  275. AssertF(this->pdcb);
  276. return dwUsage == this->pdcb->lpVtbl->GetUsage(this->pdcb, iobj);
  277. }
  278. /*****************************************************************************
  279. *
  280. * @doc INTERNAL
  281. *
  282. * @method int | CDIDev | FindDeviceObjectFormat |
  283. *
  284. * Search the device object format table for the one that
  285. * matches the guid in question.
  286. *
  287. * @parm PCODF | podf |
  288. *
  289. * The object to locate. If the <e DIOBJECTDATAFORMAT.rguid>
  290. * is null, then the field is a wildcard.
  291. *
  292. * If the <e DIOBJECTDATAFORMAT.dwType> specifies
  293. * <c DIDFT_ANYINSTANCE>, then any instance will be accepted.
  294. *
  295. * @parm PDIXLAT | pdix |
  296. *
  297. * The partial translation table so far. This is used to find
  298. * an empty slot in case of wildcards.
  299. *
  300. * @returns
  301. *
  302. * Returns the index of the object that matches, or -1 if
  303. * the object is not supported by the device.
  304. *
  305. * Someday: Should fall back to best match if types don't match.
  306. *
  307. *****************************************************************************/
  308. int INTERNAL
  309. CDIDev_FindDeviceObjectFormat(PDD this, PCODF podf, PDIXLAT pdix)
  310. {
  311. PCODF podfD; /* The format in the device */
  312. UINT iobj;
  313. /*
  314. * We must count upwards, so that first-fit chooses the smallest one.
  315. */
  316. for ( iobj = 0; iobj < this->df.dwNumObjs; iobj++ ) {
  317. podfD = &this->df.rgodf[iobj];
  318. if (
  319. /*
  320. * Type needs to match.
  321. *
  322. * Note that works for output-only actuators:
  323. * Since you cannot read from an output-only
  324. * actuator, you can't put it in a data format.
  325. *
  326. */
  327. (podf->dwType & DIDFT_TYPEVALID & podfD->dwType)
  328. /*
  329. * Attributes need to match.
  330. */
  331. && fHasAllBitsFlFl(podfD->dwType, podf->dwType & DIDFT_ATTRVALID)
  332. /*
  333. * Slot needs to be empty.
  334. */
  335. && pdix[iobj].dwOfs == 0xFFFFFFFF
  336. /*
  337. * "If there is a guid/usage, it must match."
  338. *
  339. * If pguid is NULL, then the match is vacuous.
  340. *
  341. * If DIDOI_GUIDISUSAGE is clear, then pguid points to
  342. * a real GUID. GUID_NULL means "Don't care" and matches
  343. * anything. Otherwise, it must match the actual GUID.
  344. *
  345. * If DIDOI_GUIDISUSAGE is set, then pguid is really
  346. * a DIMAKEUSAGEDWORD of the usage and usage page,
  347. * which we compare against the same in the object.
  348. */
  349. && (podf->pguid == 0 ||
  350. ((podf->dwFlags & DIDOI_GUIDISUSAGE) ?
  351. CDIDev_IsMatchingUsage(this, (DWORD)(UINT_PTR)podf->pguid, iobj) :
  352. CDIDev_IsMatchingGUID(this, podf->pguid, podfD->pguid)))
  353. /*
  354. * If there is an instance number, it must match.
  355. */
  356. && fLimpFF((podf->dwType & DIDFT_ANYINSTANCE) !=
  357. DIDFT_ANYINSTANCE,
  358. fEqualMaskFlFl(DIDFT_ANYINSTANCE,
  359. podf->dwType, podfD->dwType))
  360. /*
  361. * If there is an aspect, it must match.
  362. *
  363. * If the device data format doesn't specify an aspect,
  364. * then that counts as a free match too.
  365. */
  366. && fLimpFF((podf->dwFlags & DIDOI_ASPECTMASK) &&
  367. (podfD->dwFlags & DIDOI_ASPECTMASK),
  368. fEqualMaskFlFl(DIDOI_ASPECTMASK,
  369. podf->dwFlags, podfD->dwFlags))
  370. ) { /* Criterion matches, woo-hoo */
  371. return iobj;
  372. }
  373. }
  374. return -1;
  375. }
  376. /*****************************************************************************
  377. *
  378. * @doc INTERNAL
  379. *
  380. * @method HRESULT | CDIDev | ParseDataFormat |
  381. *
  382. * Parse the data format passed by the application and
  383. * convert it into a format that we can use to translate
  384. * the device data into application data.
  385. *
  386. * @parm IN LPDIDATAFORMAT | lpdf |
  387. *
  388. * Points to a structure that describes the format of the data
  389. * the DirectInputDevice should return.
  390. *
  391. * @returns
  392. *
  393. * Returns a COM error code. The following error codes are
  394. * intended to be illustrative and not necessarily comprehensive.
  395. *
  396. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  397. *
  398. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: The
  399. * <p lpvData> parameter is not a valid pointer.
  400. *
  401. * <c DIERR_ACQUIRED>: Cannot change the data format while the
  402. * device is acquired.
  403. *
  404. *
  405. *****************************************************************************/
  406. STDMETHODIMP
  407. CDIDev_ParseDataFormat(PDD this, const DIDATAFORMAT *lpdf)
  408. {
  409. PDIXLAT pdix;
  410. // Prefix: Whistler 45081
  411. PINT rgiobj = NULL;
  412. HRESULT hres;
  413. DIPROPDWORD dipdw;
  414. VXDDATAFORMAT vdf;
  415. #ifdef DEBUG
  416. EnterProc(CDIDev_ParseDataFormat, (_ "pp", this, lpdf));
  417. #else
  418. EnterProcR(IDirectInputDevice8::SetDataFormat, (_ "pp", this, lpdf));
  419. #endif
  420. /*
  421. * Caller should've nuked the old translation table.
  422. */
  423. AssertF(this->pdix == 0);
  424. AssertF(this->rgiobj == 0);
  425. AssertF(this->cdwPOV == 0);
  426. vdf.cbData = this->df.dwDataSize;
  427. vdf.pDfOfs = 0;
  428. if ( SUCCEEDED(hres = AllocCbPpv(cbCxX(this->df.dwNumObjs, DIXLAT), &pdix)) &&
  429. SUCCEEDED(hres = AllocCbPpv(cbCdw(this->df.dwDataSize), &vdf.pDfOfs)) &&
  430. SUCCEEDED(hres = AllocCbPpv(cbCdw(lpdf->dwDataSize), &rgiobj)) &&
  431. SUCCEEDED(hres =
  432. ReallocCbPpv(cbCdw(lpdf->dwNumObjs), &this->rgdwPOV)) ) {
  433. UINT iobj;
  434. /*
  435. * Pre-init all the translation tags to -1,
  436. * which means "not in use"
  437. */
  438. memset(pdix, 0xFF, cbCxX(this->df.dwNumObjs, DIXLAT));
  439. memset(vdf.pDfOfs, 0xFF, cbCdw(this->df.dwDataSize));
  440. memset(rgiobj, 0xFF, cbCdw(lpdf->dwDataSize));
  441. SquirtSqflPtszV(sqflDf | sqflVerbose, TEXT("Begin parse data format"));
  442. for ( iobj = 0; iobj < lpdf->dwNumObjs; iobj++ ) {
  443. PCODF podf = &lpdf->rgodf[iobj];
  444. SquirtSqflPtszV(sqflDf | sqflVerbose, TEXT("Object %2d: offset %08x"),
  445. iobj, podf->dwOfs);
  446. /*
  447. * Note that the podf->dwOfs < lpdf->dwDataSize test is safe
  448. * even for DWORD objects, since we also check that both
  449. * values are DWORD multiples.
  450. */
  451. if ( ((podf->dwFlags & DIDOI_GUIDISUSAGE) ||
  452. fLimpFF(podf->pguid,
  453. SUCCEEDED(hres = hresFullValidGuid(podf->pguid, 1)))) &&
  454. podf->dwOfs < lpdf->dwDataSize ) {
  455. int iobjDev = CDIDev_FindDeviceObjectFormat(this, podf, pdix);
  456. if ( iobjDev != -1 ) {
  457. PCODF podfFound = &this->df.rgodf[iobjDev];
  458. if ( podfFound->dwType & DIDFT_DWORDOBJS ) {
  459. if ( (podf->dwOfs & 3) == 0 ) {
  460. } else {
  461. RPF("%s: Dword objects must be aligned", s_szProc);
  462. goto fail;
  463. }
  464. }
  465. pdix[iobjDev].dwOfs = podf->dwOfs;
  466. rgiobj[podf->dwOfs] = iobjDev;
  467. vdf.pDfOfs[podfFound->dwOfs] = iobjDev;
  468. if ( podfFound->dwFlags & DIDOI_POLLED ) {
  469. this->fPolledDataFormat = TRUE;
  470. }
  471. dipdw.diph.dwSize = sizeof(DIPROPDWORD);
  472. dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
  473. dipdw.diph.dwObj = podfFound->dwType;
  474. dipdw.diph.dwHow = DIPH_BYID;
  475. dipdw.dwData = 0x1; // Enable this report ID
  476. hres = CDIDev_RealSetProperty(this, DIPROP_ENABLEREPORTID, &dipdw.diph);
  477. if ( hres == E_NOTIMPL )
  478. {
  479. hres = S_OK;
  480. }
  481. else if( FAILED( hres ) )
  482. {
  483. SquirtSqflPtszV(sqflDf | sqflError,
  484. TEXT("Could not set DIPROP_ENABLEREPORTID for offset %d"),
  485. iobj);
  486. }
  487. } else if ( podf->dwType & DIDFT_OPTIONAL ) {
  488. SquirtSqflPtszV(sqflDf | sqflVerbose,
  489. TEXT("Object %2d: Skipped (optional)"),
  490. iobj);
  491. /*
  492. * We need to remember where the failed POVs live
  493. * so we can neutralize them in GetDeviceState().
  494. */
  495. if ( podf->dwType & DIDFT_POV ) {
  496. AssertF(this->cdwPOV < lpdf->dwNumObjs);
  497. this->rgdwPOV[this->cdwPOV++] = podf->dwOfs;
  498. }
  499. } else {
  500. RPF("%s: Format not compatible with device", s_szProc);
  501. goto fail;
  502. }
  503. } else {
  504. if ( podf->dwOfs >= lpdf->dwDataSize ) {
  505. RPF("%s: rgodf[%d].dwOfs of 0x%08x out of range in data format",
  506. s_szProc, iobj, podf->dwOfs );
  507. }
  508. fail:;
  509. hres = E_INVALIDARG;
  510. goto done;
  511. }
  512. }
  513. #ifdef DEBUG
  514. /*
  515. * Double-check the lookup tables just to preserve our sanity.
  516. */
  517. {
  518. UINT dwOfs;
  519. for ( dwOfs = 0; dwOfs < lpdf->dwDataSize; dwOfs++ ) {
  520. if ( rgiobj[dwOfs] >= 0 ) {
  521. AssertF(pdix[rgiobj[dwOfs]].dwOfs == dwOfs);
  522. } else {
  523. AssertF(rgiobj[dwOfs] == -1);
  524. }
  525. }
  526. }
  527. #endif
  528. /*
  529. * Shrink the "failed POV" array to its actual size.
  530. * The shrink "should" always succeed. Note also that
  531. * even if it fails, we're okay; we just waste a little
  532. * memory.
  533. */
  534. hres = ReallocCbPpv(cbCdw(this->cdwPOV), &this->rgdwPOV);
  535. AssertF(SUCCEEDED(hres));
  536. /*
  537. * If we are using cooked data, then we actually hand the
  538. * device driver a different translation table which
  539. * combines the offset and dwDevType so data cooking can
  540. * happen safely.
  541. */
  542. vdf.pvi = this->pvi;
  543. if ( fLimpFF(this->pvi,
  544. SUCCEEDED(hres = Hel_SetDataFormat(&vdf))) ) {
  545. this->pdix = pdix;
  546. pdix = 0;
  547. this->rgiobj = rgiobj;
  548. rgiobj = 0;
  549. this->dwDataSize = lpdf->dwDataSize;
  550. hres = S_OK;
  551. } else {
  552. AssertF(FAILED(hres));
  553. }
  554. } else {
  555. /* Out of memory */
  556. }
  557. done:;
  558. FreePpv(&pdix);
  559. FreePpv(&rgiobj);
  560. FreePpv(&vdf.pDfOfs);
  561. ExitOleProc();
  562. return hres;
  563. }
  564. /*****************************************************************************
  565. *
  566. * @doc INTERNAL
  567. *
  568. * @method HRESULT | CDIDev | OptimizeDataFormat |
  569. *
  570. * Study the parsed data format to determine whether we can
  571. * used an optimized <mf CDIDev::GetDeviceState> to obtain
  572. * the data more quickly.
  573. *
  574. * The data format is considered optimized if it matches the
  575. * device data format, modulo possible shifting due to insertion
  576. * of bonus fields at the beginning or end, and modulo missing
  577. * fields.
  578. *
  579. * The data format is considered fully-optimized if it
  580. * optimized, and no shifting is necessary, and the structure size
  581. * is exactly the same. This means the buffer can be passed
  582. * straight through to the driver.
  583. *
  584. *
  585. *****************************************************************************/
  586. HRESULT INTERNAL
  587. CDIDev_OptimizeDataFormat(PDD this)
  588. {
  589. int ib;
  590. DWORD ibMax; /* One past highest match point */
  591. DWORD ibMin; /* Lowest match point */
  592. int iobj;
  593. DWORD dwDataSize;
  594. HRESULT hres;
  595. EnterProc(CDIDev_OptimizeDataFormat, (_ "p", this));
  596. ib = (int)0x8000000; /* Not yet known */
  597. ibMin = 0xFFFFFFFF;
  598. ibMax = 0;
  599. for ( iobj = this->df.dwNumObjs; --iobj >= 0; ) {
  600. DWORD ibMaxThis;
  601. if ( this->pdix[iobj].dwOfs != 0xFFFFFFFF ) { /* Data was requested */
  602. int ibExpected = (int)(this->pdix[iobj].dwOfs -
  603. this->df.rgodf[iobj].dwOfs);
  604. if ( fLimpFF(ib != (int)0x8000000, ib == ibExpected) ) {
  605. ib = ibExpected;
  606. } else {
  607. SquirtSqflPtszV(sqfl | sqflMajor,
  608. TEXT("IDirectInputDevice: Optimization level 0, translation needed") );
  609. this->diopt = dioptNone;
  610. this->GetState = CDIDev_GetDeviceStateSlow;
  611. goto done;
  612. }
  613. if ( ibMin > this->df.rgodf[iobj].dwOfs ) {
  614. ibMin = this->df.rgodf[iobj].dwOfs;
  615. }
  616. if ( this->df.rgodf[iobj].dwType & DIDFT_DWORDOBJS ) {
  617. ibMaxThis = this->df.rgodf[iobj].dwOfs + sizeof(DWORD);
  618. } else {
  619. ibMaxThis = this->df.rgodf[iobj].dwOfs + sizeof(BYTE);
  620. }
  621. if ( ibMax < ibMaxThis ) {
  622. ibMax = ibMaxThis;
  623. }
  624. }
  625. }
  626. /*
  627. * Make sure we actually found something.
  628. */
  629. if ( ib != (int)0x8000000 ) { /* Data format is matched */
  630. AssertF(ibMin < ibMax);
  631. AssertF(ib + (int)ibMin >= 0);
  632. AssertF(ib + ibMax <= this->dwDataSize);
  633. this->ibDelta = ib;
  634. this->ibMin = ibMin;
  635. this->cbMatch = ibMax - ibMin;
  636. if ( ib >= 0 && ib + this->df.dwDataSize <= this->dwDataSize ) {
  637. /* We can go direct */
  638. if ( ib == 0 && this->dwDataSize == this->df.dwDataSize ) {
  639. /* Data formats are equal! */
  640. this->diopt = dioptEqual;
  641. this->GetState = CDIDev_GetDeviceStateEqual;
  642. SquirtSqflPtszV(sqfl | sqflMajor,
  643. TEXT("IDirectInputDevice: Optimization level 3, full speed ahead!") );
  644. } else {
  645. this->diopt = dioptDirect;
  646. this->GetState = CDIDev_GetDeviceStateDirect;
  647. SquirtSqflPtszV(sqfl | sqflMajor,
  648. TEXT("IDirectInputDevice: Optimization level 2, direct access") );
  649. }
  650. } else {
  651. SquirtSqflPtszV(sqfl | sqflMajor,
  652. TEXT("IDirectInputDevice: Optimization level 1, okay") );
  653. this->diopt = dioptMatch;
  654. this->GetState = CDIDev_GetDeviceStateMatched;
  655. }
  656. } else { /* No data in data format! */
  657. RPF("IDirectInputDevice: Null data format; if that's what you want...");
  658. this->diopt = dioptNone;
  659. this->GetState = CDIDev_GetDeviceStateSlow;
  660. }
  661. done:;
  662. if ( this->diopt >= dioptDirect ) { /* Can go direct; don't need buf */
  663. dwDataSize = 0;
  664. } else {
  665. dwDataSize = this->df.dwDataSize;
  666. }
  667. hres = ReallocCbPpv(dwDataSize, &this->pvBuffer);
  668. if ( SUCCEEDED(hres) ) {
  669. AssertF(this->GetState);
  670. } else {
  671. FreePpv(&this->pdix);
  672. D(this->GetState = 0);
  673. }
  674. return hres;
  675. }
  676. /*****************************************************************************
  677. *
  678. * @doc EXTERNAL
  679. *
  680. * @method HRESULT | IDirectInputDevice | SetDataFormat |
  681. *
  682. * Set the data format for the DirectInput device.
  683. *
  684. * The data format must be set before the device can be
  685. * acquired.
  686. *
  687. * It is necessary to set the data format only once.
  688. *
  689. * The data format may not be changed while the device
  690. * is acquired.
  691. *
  692. * If the attempt to set the data format fails, all data
  693. * format information is lost, and a valid data format
  694. * must be set before the device may be acquired.
  695. *
  696. * @cwrap LPDIRECTINPUTDEVICE | lpDirectInputDevice
  697. *
  698. * @parm IN LPDIDATAFORMAT | lpdf |
  699. *
  700. * Points to a structure that describes the format of the data
  701. * the DirectInputDevice should return.
  702. *
  703. * @returns
  704. *
  705. * Returns a COM error code. The following error codes are
  706. * intended to be illustrative and not necessarily comprehensive.
  707. *
  708. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  709. *
  710. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: The
  711. * <p lpvData> parameter is not a valid pointer.
  712. *
  713. * <c DIERR_ACQUIRED>: Cannot change the data format while the
  714. * device is acquired.
  715. *
  716. *
  717. *****************************************************************************/
  718. HRESULT INLINE
  719. CDIDev_SetDataFormat_IsValidDataSize(LPCDIDATAFORMAT lpdf)
  720. {
  721. HRESULT hres;
  722. if ( lpdf->dwDataSize % 4 == 0 ) {
  723. hres = S_OK;
  724. } else {
  725. RPF("IDirectInputDevice::SetDataFormat: "
  726. "dwDataSize must be a multiple of 4");
  727. hres = E_INVALIDARG;
  728. }
  729. return hres;
  730. }
  731. HRESULT INLINE
  732. CDIDev_SetDataFormat_IsValidObjectSize(LPCDIDATAFORMAT lpdf)
  733. {
  734. HRESULT hres;
  735. if ( lpdf->dwObjSize == cbX(ODF) ) {
  736. hres = S_OK;
  737. } else {
  738. RPF("IDirectInputDevice::SetDataFormat: Invalid dwObjSize");
  739. hres = E_INVALIDARG;
  740. }
  741. return hres;
  742. }
  743. STDMETHODIMP
  744. CDIDev_SetDataFormat(PV pdd, LPCDIDATAFORMAT lpdf _THAT)
  745. {
  746. HRESULT hres;
  747. EnterProcR(IDirectInputDevice8::SetDataFormat, (_ "pp", pdd, lpdf));
  748. if ( SUCCEEDED(hres = hresPvT(pdd)) &&
  749. SUCCEEDED(hres = hresFullValidReadPxCb(lpdf, DIDATAFORMAT, 1)) &&
  750. SUCCEEDED(hres = hresFullValidFl(lpdf->dwFlags, DIDF_VALID, 1)) &&
  751. SUCCEEDED(hres = CDIDev_SetDataFormat_IsValidDataSize(lpdf)) &&
  752. SUCCEEDED(hres = CDIDev_SetDataFormat_IsValidObjectSize(lpdf)) &&
  753. SUCCEEDED(hres = hresFullValidReadPvCb(lpdf->rgodf,
  754. cbCxX(lpdf->dwNumObjs, ODF), 1)) ) {
  755. PDD this = _thisPv(pdd);
  756. /*
  757. * Must protect with the critical section to prevent two people
  758. * from changing the format simultaneously, or one person from
  759. * changing the data format while somebody else is reading data.
  760. */
  761. CDIDev_EnterCrit(this);
  762. AssertF( this->dwVersion );
  763. if ( !this->fAcquired ) {
  764. DIPROPDWORD dipdw;
  765. /*
  766. * Nuke the old data format stuff before proceeding.
  767. */
  768. FreePpv(&this->pdix);
  769. FreePpv(&this->rgiobj);
  770. this->cdwPOV = 0;
  771. D(this->GetState = 0);
  772. this->fPolledDataFormat = FALSE;
  773. /*
  774. * Wipe out the report IDs
  775. */
  776. dipdw.diph.dwSize = sizeof(DIPROPDWORD);
  777. dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
  778. dipdw.diph.dwObj = 0x0;
  779. dipdw.diph.dwHow = DIPH_DEVICE;
  780. dipdw.dwData = 0; // Nuke all knowledge of reportId's
  781. hres = CDIDev_RealSetProperty(this, DIPROP_ENABLEREPORTID, &dipdw.diph);
  782. if ( SUCCEEDED(hres) || hres == E_NOTIMPL )
  783. {
  784. hres = CDIDev_ParseDataFormat(this, lpdf);
  785. if ( SUCCEEDED(hres) ) {
  786. hres = CDIDev_OptimizeDataFormat(this);
  787. /*
  788. * Now set the axis mode, as a convenience.
  789. */
  790. CAssertF(DIDF_VALID == (DIDF_RELAXIS | DIDF_ABSAXIS));
  791. switch ( lpdf->dwFlags ) {
  792. case 0:
  793. hres = S_OK;
  794. goto axisdone;
  795. case DIDF_RELAXIS:
  796. dipdw.dwData = DIPROPAXISMODE_REL;
  797. break;
  798. case DIDF_ABSAXIS:
  799. dipdw.dwData = DIPROPAXISMODE_ABS;
  800. break;
  801. default:
  802. RPF("%s: Cannot combine DIDF_RELAXIS with DIDF_ABSAXIS",
  803. s_szProc);
  804. hres = E_INVALIDARG;
  805. goto axisdone;
  806. }
  807. dipdw.diph.dwSize = sizeof(DIPROPDWORD);
  808. dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
  809. dipdw.diph.dwObj = 0;
  810. dipdw.diph.dwHow = DIPH_DEVICE;
  811. hres = CDIDev_RealSetProperty(this, DIPROP_AXISMODE, &dipdw.diph);
  812. if ( SUCCEEDED(hres) ) {
  813. hres = S_OK;
  814. }
  815. }
  816. } else
  817. {
  818. SquirtSqflPtszV(sqflDf,
  819. TEXT("Could not set DIPROP_ENABLEREPORTID to 0x0"));
  820. }
  821. axisdone:;
  822. } else { /* Already acquired */
  823. hres = DIERR_ACQUIRED;
  824. }
  825. CDIDev_LeaveCrit(this);
  826. }
  827. ExitOleProcR();
  828. return hres;
  829. }
  830. #define BEGIN_CONST_DATA data_seg(".text", "CODE")
  831. BYTE c_SemTypeToDFType[8] = { 0, 0,
  832. DIDFT_GETTYPE(DIDFT_ABSAXIS), DIDFT_GETTYPE(DIDFT_RELAXIS),
  833. DIDFT_GETTYPE(DIDFT_BUTTON), 0,
  834. DIDFT_GETTYPE(DIDFT_POV), 0 };
  835. #define END_CONST_DATA data_seg(".data", "DATA")
  836. /*****************************************************************************
  837. *
  838. * @doc INTERNAL
  839. *
  840. * @struct DEVICETOUSER |
  841. *
  842. * Structure to hold a device to user assignment.
  843. *
  844. * @field GUID | guidDevice |
  845. *
  846. * The device.
  847. *
  848. * @field WCHAR | wszOwner[MAX_PATH] |
  849. *
  850. * Name of the user who currently owns the device.
  851. *
  852. *****************************************************************************/
  853. typedef struct _DEVICETOUSER
  854. {
  855. GUID guidDevice;
  856. WCHAR wszOwner[MAX_PATH];
  857. } DEVICETOUSER, *PDEVICETOUSER;
  858. #define DELTA_DTO_COUNT 4
  859. // ISSUE-2001/03/29-MarcAnd CMap usage is inconsistant
  860. // CMap code should be split out into separate source file
  861. /*****************************************************************************
  862. *
  863. * @doc INTERNAL
  864. *
  865. * @func HRESULT | CMap_SetDeviceUserName |
  866. *
  867. * Set the passed device to be associated with the passed user name.
  868. * If the device is already associated with a user or with no user
  869. * that association is replaced with the new one. If the device is
  870. * not yet in the array, it is added. Memory is allocated as
  871. * necessary to increase the array size.
  872. *
  873. * @parm REFGUID | guidDevInst |
  874. *
  875. * A pointer to the device instance GUID to be added/modified.
  876. *
  877. * @parm LPCWSTR | wszOwner |
  878. *
  879. * A UNICODE user name.
  880. *
  881. * @returns
  882. *
  883. * <c S_OK> if the name was set
  884. * <c DI_NOEFFECT> if nothing was set because nothing needed to be
  885. * A memory allocation error if such occured.
  886. *
  887. *****************************************************************************/
  888. HRESULT CMap_SetDeviceUserName
  889. (
  890. REFGUID guidDevInst,
  891. LPCWSTR wszOwner
  892. )
  893. {
  894. HRESULT hres = S_OK;
  895. PDEVICETOUSER pdto;
  896. CAssertF( DELTA_DTO_COUNT > 1 );
  897. AssertF( !IsEqualGUID( guidDevInst, &GUID_Null ) );
  898. AssertF( !InCrit() );
  899. DllEnterCrit();
  900. /*
  901. * Note g_pdto will be NULL until the first name is set
  902. * however, g_cdtoMax will be zero so this loop should
  903. * fall through to allocate more memory.
  904. */
  905. for( pdto = g_pdto; pdto < &g_pdto[ g_cdtoMax ]; pdto++ )
  906. {
  907. if( IsEqualGUID( guidDevInst, &pdto->guidDevice ) )
  908. {
  909. break;
  910. }
  911. }
  912. if( !wszOwner )
  913. {
  914. if( pdto < &g_pdto[ g_cdtoMax ] )
  915. {
  916. ZeroMemory( &pdto->guidDevice, cbX( pdto->guidDevice ) );
  917. g_cdto--;
  918. AssertF( g_cdto >= 0 );
  919. }
  920. else
  921. {
  922. /*
  923. * Could not find device, since we were removing, don't worry
  924. */
  925. hres = DI_NOEFFECT;
  926. }
  927. }
  928. else
  929. {
  930. if( pdto >= &g_pdto[ g_cdtoMax ] )
  931. {
  932. /*
  933. * Need to add a new entry
  934. */
  935. if( g_cdto == g_cdtoMax )
  936. {
  937. /*
  938. * If all entries are used try to get more
  939. */
  940. hres = ReallocCbPpv( ( g_cdtoMax + DELTA_DTO_COUNT ) * cbX( *g_pdto ), &g_pdto );
  941. if( FAILED( hres ) )
  942. {
  943. goto exit_SetDeviceUserName;
  944. }
  945. g_cdtoMax += DELTA_DTO_COUNT;
  946. /*
  947. * The first new element is sure to be free
  948. */
  949. pdto = &g_pdto[ g_cdto ];
  950. }
  951. else
  952. {
  953. /*
  954. * There's an empty one in the array somewhere
  955. */
  956. for( pdto = g_pdto; pdto < &g_pdto[ g_cdtoMax ]; pdto++ )
  957. {
  958. if( IsEqualGUID( &GUID_Null, &pdto->guidDevice ) )
  959. {
  960. break;
  961. }
  962. }
  963. }
  964. pdto->guidDevice = *guidDevInst;
  965. }
  966. g_cdto++;
  967. AssertF( pdto < &g_pdto[ g_cdtoMax ] );
  968. AssertF( lstrlenW( wszOwner ) < cbX( pdto->wszOwner ) );
  969. #ifdef WINNT
  970. lstrcpyW( pdto->wszOwner, wszOwner );
  971. #else
  972. memcpy( pdto->wszOwner, wszOwner, ( 1 + lstrlenW( wszOwner ) ) * cbX( *wszOwner ) );
  973. #endif
  974. }
  975. exit_SetDeviceUserName:;
  976. DllLeaveCrit();
  977. return hres;
  978. }
  979. /*****************************************************************************
  980. *
  981. * @doc INTERNAL
  982. *
  983. * @func HRESULT | CMap_IsNewDeviceUserName |
  984. *
  985. * Searches the array of device to user associations for the passed
  986. * device GUID. If the device GUID is matched the name is tested
  987. * to see if it is the same as the passed name.
  988. *
  989. * @parm REFGUID | guidDevInst |
  990. *
  991. * A pointer to the device instance GUID to be tested.
  992. *
  993. * @parm LPCWSTR | wszOwner |
  994. *
  995. * A UNICODE user name to be tested.
  996. *
  997. * @returns
  998. *
  999. * <c FALSE> if a the device was found and the user matches
  1000. * <c TRUE> if not
  1001. *
  1002. *****************************************************************************/
  1003. HRESULT CMap_IsNewDeviceUserName
  1004. (
  1005. REFGUID guidDevInst,
  1006. LPWSTR wszTest
  1007. )
  1008. {
  1009. BOOL fres = TRUE;
  1010. PDEVICETOUSER pdto;
  1011. AssertF( !IsEqualGUID( guidDevInst, &GUID_Null ) );
  1012. AssertF( wszTest != L'\0' );
  1013. AssertF( !InCrit() );
  1014. DllEnterCrit();
  1015. if( g_pdto )
  1016. {
  1017. for( pdto = g_pdto; pdto < &g_pdto[ g_cdtoMax ]; pdto++ )
  1018. {
  1019. if( IsEqualGUID( guidDevInst, &pdto->guidDevice ) )
  1020. {
  1021. #ifdef WINNT
  1022. if( !lstrcmpW( wszTest, pdto->wszOwner ) )
  1023. #else
  1024. if( ( pdto->wszOwner[0] != L'\0' )
  1025. &&( !memcmp( wszTest, pdto->wszOwner,
  1026. lstrlenW( wszTest ) * cbX( *wszTest ) ) ) )
  1027. #endif
  1028. {
  1029. fres = FALSE;
  1030. }
  1031. break;
  1032. }
  1033. }
  1034. }
  1035. DllLeaveCrit();
  1036. return fres;
  1037. }
  1038. /*****************************************************************************
  1039. *
  1040. * @doc INTERNAL
  1041. *
  1042. * @func HRESULT | CMap_GetDeviceUserName |
  1043. *
  1044. * Searches the array of device to user associations for the passed
  1045. * device GUID. If the device GUID is matched and has an associated
  1046. * user name, that is copied into wszOwner. If the GUID is not
  1047. * matched or the match has a NULL string associated with it,
  1048. * wszOwner is set to a NULL string.
  1049. *
  1050. * @parm REFGUID | guidDevInst |
  1051. *
  1052. * A pointer to the device instance GUID to be added/modified.
  1053. *
  1054. * @parm LPCWSTR | wszOwner |
  1055. *
  1056. * A UNICODE user name.
  1057. *
  1058. * @returns
  1059. *
  1060. * <c S_OK> if a user name has been copied into wszOwner
  1061. * <c DI_NOEFFECT> if wszOwner has been set to a NULL string
  1062. *
  1063. *****************************************************************************/
  1064. HRESULT CMap_GetDeviceUserName
  1065. (
  1066. REFGUID guidDevInst,
  1067. LPWSTR wszOwner
  1068. )
  1069. {
  1070. HRESULT hres = DI_NOEFFECT;
  1071. PDEVICETOUSER pdto;
  1072. AssertF( !IsEqualGUID( guidDevInst, &GUID_Null ) );
  1073. AssertF( !InCrit() );
  1074. /*
  1075. * Assume nothing is found
  1076. */
  1077. wszOwner[0] = L'\0';
  1078. DllEnterCrit();
  1079. if( g_pdto )
  1080. {
  1081. for( pdto = g_pdto; pdto < &g_pdto[ g_cdtoMax ]; pdto++ )
  1082. {
  1083. if( IsEqualGUID( guidDevInst, &pdto->guidDevice ) )
  1084. {
  1085. if( pdto->wszOwner[0] != L'\0' )
  1086. {
  1087. #ifdef WINNT
  1088. lstrcpyW( wszOwner, pdto->wszOwner );
  1089. #else
  1090. memcpy( wszOwner, pdto->wszOwner,
  1091. ( 1 + lstrlenW( pdto->wszOwner ) ) * cbX( *wszOwner ) );
  1092. #endif
  1093. hres = S_OK;
  1094. }
  1095. break;
  1096. }
  1097. }
  1098. }
  1099. DllLeaveCrit();
  1100. return hres;
  1101. }
  1102. /*****************************************************************************
  1103. *
  1104. * @doc INTERNAL
  1105. *
  1106. * @method HRESULT | CMap | ValidateActionMapSemantics |
  1107. *
  1108. * Validate the semantics in an action map for overall sanity.
  1109. *
  1110. * @parm LPDIACTIONFORMATW | pActionFormat |
  1111. *
  1112. * Actions to map.
  1113. *
  1114. * @parm DWORD | dwFlags |
  1115. *
  1116. * Flags to modify the validation behavior.
  1117. * Currently these are the <c DIDBAM_*> flags as the only
  1118. * <mf IDirectInputDevice::SetActionMap> flag is the default
  1119. * <c DIDSAM_DEFAULT>.
  1120. *
  1121. * @returns
  1122. *
  1123. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  1124. *
  1125. *
  1126. *****************************************************************************/
  1127. int __stdcall CompareActions
  1128. (
  1129. PV pv1,
  1130. PV pv2
  1131. )
  1132. {
  1133. int iRes;
  1134. LPDIACTION pAct1 = (LPDIACTION)pv1;
  1135. LPDIACTION pAct2 = (LPDIACTION)pv2;
  1136. iRes = memcmp( &pAct1->guidInstance, &pAct2->guidInstance, cbX(pAct1->guidInstance) );
  1137. if( !iRes )
  1138. {
  1139. if( pAct1->dwFlags & DIA_APPMAPPED )
  1140. {
  1141. if( pAct2->dwFlags & DIA_APPMAPPED )
  1142. {
  1143. iRes = pAct1->dwObjID - pAct2->dwObjID;
  1144. }
  1145. else
  1146. {
  1147. iRes = -1;
  1148. }
  1149. }
  1150. else
  1151. {
  1152. if( pAct2->dwFlags & DIA_APPMAPPED )
  1153. {
  1154. iRes = 1;
  1155. }
  1156. else
  1157. {
  1158. iRes = pAct1->dwSemantic - pAct2->dwSemantic;
  1159. }
  1160. }
  1161. }
  1162. return iRes;
  1163. }
  1164. STDMETHODIMP
  1165. CMap_ValidateActionMapSemantics
  1166. (
  1167. LPDIACTIONFORMATW paf,
  1168. DWORD dwFlags
  1169. )
  1170. {
  1171. HRESULT hres;
  1172. LPDIACTIONW pAction;
  1173. LPDIACTIONW *pWorkSpace;
  1174. LPDIACTIONW *pCurr;
  1175. LPDIACTIONW *pLast;
  1176. EnterProcI(IDirectInputDeviceCallback::CMap::ValidateActionMapSemantics,
  1177. (_ "px", paf, dwFlags ));
  1178. /*
  1179. * Create a pointer array to the actions, sort it then look for duplicates
  1180. */
  1181. if( SUCCEEDED( hres = AllocCbPpv( cbCxX(paf->dwNumActions,PV), &pWorkSpace) ) )
  1182. {
  1183. /*
  1184. * Fill work space from action array discarding unmappable elements
  1185. */
  1186. pCurr = pWorkSpace;
  1187. for( pAction = paf->rgoAction; pAction < &paf->rgoAction[paf->dwNumActions]; pAction++ )
  1188. {
  1189. if( dwFlags & ( DIDBAM_INITIALIZE | DIDBAM_HWDEFAULTS ) )
  1190. {
  1191. pAction->dwFlags = 0;
  1192. pAction->guidInstance = GUID_Null;
  1193. pAction->dwHow = 0;
  1194. }
  1195. else
  1196. {
  1197. if( pAction->dwFlags & ~DIA_VALID )
  1198. {
  1199. RPF( "ERROR Invalid action: rgoAction[%d].dwFlags 0x%08x",
  1200. pAction - paf->rgoAction, pAction->dwFlags & ~DIA_VALID );
  1201. pAction->dwHow = DIAH_ERROR;
  1202. hres = DIERR_INVALIDPARAM;
  1203. goto free_and_exit;
  1204. }
  1205. if( pAction->dwFlags & DIA_APPNOMAP )
  1206. {
  1207. continue;
  1208. }
  1209. if( dwFlags & DIDBAM_PRESERVE )
  1210. {
  1211. switch( pAction->dwHow )
  1212. {
  1213. case DIAH_UNMAPPED:
  1214. break;
  1215. case DIAH_USERCONFIG:
  1216. case DIAH_APPREQUESTED:
  1217. case DIAH_HWAPP:
  1218. case DIAH_HWDEFAULT:
  1219. case DIAH_OTHERAPP:
  1220. case DIAH_DEFAULT:
  1221. if( IsEqualGUID( &pAction->guidInstance, &GUID_Null ) )
  1222. {
  1223. RPF("ERROR Invalid action: rgoAction[%d].dwHow is mapped as 0x%08x but has no device",
  1224. pAction - paf->rgoAction, pAction->dwHow );
  1225. hres = DIERR_INVALIDPARAM;
  1226. goto free_and_exit;
  1227. }
  1228. break;
  1229. case DIAH_ERROR:
  1230. RPF("ERROR Invalid action: rgoAction[%d].dwHow has DIAH_ERROR",
  1231. pAction - paf->rgoAction );
  1232. hres = DIERR_INVALIDPARAM;
  1233. goto free_and_exit;
  1234. default:
  1235. if( pAction->dwHow & ~DIAH_VALID )
  1236. {
  1237. RPF("ERROR Invalid action: rgoAction[%d].dwHow has invalid flags 0x%08x",
  1238. pAction - paf->rgoAction, pAction->dwHow & ~DIAH_VALID );
  1239. }
  1240. else
  1241. {
  1242. RPF("ERROR Invalid action: rgoAction[%d].dwHow has invalid combination of map flags 0x%08x",
  1243. pAction - paf->rgoAction, pAction->dwHow & ~DIAH_VALID );
  1244. }
  1245. pAction->dwHow = DIAH_ERROR;
  1246. hres = DIERR_INVALIDPARAM;
  1247. goto free_and_exit;
  1248. }
  1249. }
  1250. else
  1251. {
  1252. if(!( pAction->dwFlags & DIA_APPMAPPED ) )
  1253. {
  1254. pAction->guidInstance = GUID_Null;
  1255. }
  1256. pAction->dwHow = 0;
  1257. }
  1258. }
  1259. if( ( pAction->dwSemantic ^ paf->dwGenre ) & DISEM_GENRE_MASK )
  1260. {
  1261. switch( DISEM_GENRE_GET( pAction->dwSemantic ) )
  1262. {
  1263. case DISEM_GENRE_GET( DIPHYSICAL_KEYBOARD ):
  1264. case DISEM_GENRE_GET( DIPHYSICAL_MOUSE ):
  1265. case DISEM_GENRE_GET( DIPHYSICAL_VOICE ):
  1266. case DISEM_GENRE_GET( DISEMGENRE_ANY ):
  1267. break;
  1268. default:
  1269. RPF("ERROR Invalid action: rgoAction[%d].dwSemantic 0x%08x for genre 0x%08x",
  1270. pAction - paf->rgoAction, pAction->dwSemantic, paf->dwGenre );
  1271. pAction->dwHow = DIAH_ERROR;
  1272. hres = DIERR_INVALIDPARAM;
  1273. goto free_and_exit;
  1274. }
  1275. }
  1276. /*
  1277. * Note, the SEM_FLAGS are not tested, this is only to save time
  1278. * as nothing depends upon their value. This could be added.
  1279. * Semantic index 0xFF used to mean ANY so don't allow it any more
  1280. */
  1281. if(!( pAction->dwFlags & DIA_APPMAPPED )
  1282. && ( ( pAction->dwSemantic & ~DISEM_VALID )
  1283. || ( DISEM_INDEX_GET( pAction->dwSemantic ) == 0xFF )
  1284. ||!c_SemTypeToDFType[ DISEM_TYPEANDMODE_GET( pAction->dwSemantic ) ] ) )
  1285. {
  1286. RPF("ERROR Invalid action: rgoAction[%d].dwSemantic 0x%08x is invalid",
  1287. pAction - paf->rgoAction, pAction->dwSemantic );
  1288. pAction->dwHow = DIAH_ERROR;
  1289. hres = DIERR_INVALIDPARAM;
  1290. goto free_and_exit;
  1291. }
  1292. *pCurr = pAction;
  1293. pCurr++;
  1294. }
  1295. if( pCurr == pWorkSpace )
  1296. {
  1297. SquirtSqflPtszV(sqflDf | sqflBenign,
  1298. TEXT("Action map contains no mappable actions") );
  1299. hres = S_FALSE;
  1300. }
  1301. else
  1302. {
  1303. hres = S_OK;
  1304. pLast = pCurr - 1;
  1305. ptrPartialQSort( (PV)pWorkSpace, (PV)pLast, &CompareActions );
  1306. ptrInsertSort( (PV)pWorkSpace, (PV)pLast, &CompareActions );
  1307. /*
  1308. * Now we have an ordered list, see there are duplicate actions.
  1309. */
  1310. for( pCurr = pWorkSpace + 1; pCurr <= pLast; pCurr++ )
  1311. {
  1312. if( !CompareActions( *(pCurr-1), *pCurr )
  1313. && !( (*pCurr)->dwFlags & DIA_APPMAPPED ) )
  1314. {
  1315. RPF( "ERROR Invalid DIACTIONFORMAT: rgoAction contains duplicates" );
  1316. hres = DIERR_INVALIDPARAM;
  1317. #ifndef XDEBUG
  1318. /*
  1319. * In retail, any bad is bad. In debug report how bad.
  1320. */
  1321. break;
  1322. #else
  1323. SquirtSqflPtszV(sqflDf | sqflError,
  1324. TEXT("Actions %d and %d are the same"),
  1325. *(pCurr-1) - paf->rgoAction, *pCurr - paf->rgoAction );
  1326. #endif
  1327. }
  1328. }
  1329. }
  1330. free_and_exit:;
  1331. FreePv( pWorkSpace );
  1332. }
  1333. ExitOleProcR();
  1334. return hres;
  1335. }
  1336. /*****************************************************************************
  1337. *
  1338. * @doc INTERNAL
  1339. *
  1340. * @func HRESULT | CMap_TestSysObject |
  1341. *
  1342. * Test the passed object to see if it is a reasonable thing to exist
  1343. * on a mouse or keyboard depending on the physical genre.
  1344. *
  1345. * @parm DWORD | dwPhysicalGenre |
  1346. *
  1347. * Mouse, keyboard or voice as DIPHYSICAL_*
  1348. *
  1349. * @parm DWORD | dwObject |
  1350. *
  1351. * The object in question
  1352. *
  1353. * @returns
  1354. *
  1355. * <c S_OK> if the object could be expected on the class of device
  1356. * or <c DIERR_INVALIDPARAM> if not
  1357. *
  1358. *****************************************************************************/
  1359. HRESULT CMap_TestSysObject
  1360. (
  1361. DWORD dwPhysicalGenre,
  1362. DWORD dwObject
  1363. )
  1364. {
  1365. HRESULT hres = S_OK;
  1366. if( dwPhysicalGenre == DIPHYSICAL_KEYBOARD )
  1367. {
  1368. /*
  1369. * Anything but a button with an 8 bit offset is invalid.
  1370. */
  1371. if( ( dwObject & DIDFT_BUTTON )
  1372. && ( ( DIDFT_GETINSTANCE( dwObject ) & 0xFF00 ) == 0 ) )
  1373. {
  1374. SquirtSqflPtszV(sqflDf | sqflBenign,
  1375. TEXT("Key 0x%02 not defined on this keyboard (id)"),
  1376. dwObject );
  1377. }
  1378. else
  1379. {
  1380. SquirtSqflPtszV(sqflDf | sqflError,
  1381. TEXT("Object type 0x%08 invalid for keyboard (id)"),
  1382. dwObject );
  1383. hres = DIERR_INVALIDPARAM;
  1384. }
  1385. }
  1386. else if( dwPhysicalGenre == DIPHYSICAL_MOUSE )
  1387. {
  1388. /*
  1389. * Allow buttons 1 to 8 and axes 1 to 3
  1390. */
  1391. if( ( dwObject & DIDFT_PSHBUTTON )
  1392. && ( DIDFT_GETINSTANCE( dwObject ) < 8 ) )
  1393. {
  1394. SquirtSqflPtszV(sqflDf | sqflBenign,
  1395. TEXT("Button %d not defined on this mouse (id)"),
  1396. DIDFT_GETINSTANCE( dwObject ) );
  1397. }
  1398. else if( ( dwObject & DIDFT_AXIS )
  1399. && ( DIDFT_GETINSTANCE( dwObject ) < 3 ) )
  1400. {
  1401. SquirtSqflPtszV(sqflDf | sqflBenign,
  1402. TEXT("Axis %d not defined on this mouse (id)"),
  1403. DIDFT_GETINSTANCE( dwObject ) );
  1404. }
  1405. else
  1406. {
  1407. SquirtSqflPtszV(sqflDf | sqflError,
  1408. TEXT("Bad control object 0x%08x for mouse (id)"),
  1409. dwObject );
  1410. hres = DIERR_INVALIDPARAM;
  1411. }
  1412. }
  1413. else if( dwPhysicalGenre == DIPHYSICAL_VOICE )
  1414. {
  1415. if( dwObject & DIDFT_PSHBUTTON )
  1416. {
  1417. switch( DIDFT_GETINSTANCE( dwObject ) )
  1418. {
  1419. case DIVOICE_CHANNEL1:
  1420. case DIVOICE_CHANNEL2:
  1421. case DIVOICE_CHANNEL3:
  1422. case DIVOICE_CHANNEL4:
  1423. case DIVOICE_CHANNEL5:
  1424. case DIVOICE_CHANNEL6:
  1425. case DIVOICE_CHANNEL7:
  1426. case DIVOICE_CHANNEL8:
  1427. case DIVOICE_TEAM:
  1428. case DIVOICE_ALL:
  1429. case DIVOICE_RECORDMUTE:
  1430. case DIVOICE_PLAYBACKMUTE:
  1431. case DIVOICE_TRANSMIT:
  1432. case DIVOICE_VOICECOMMAND:
  1433. SquirtSqflPtszV(sqflDf | sqflBenign,
  1434. TEXT("Button %d not defined on this comms device (id)"),
  1435. DIDFT_GETINSTANCE( dwObject ) );
  1436. break;
  1437. default:
  1438. SquirtSqflPtszV(sqflDf | sqflError,
  1439. TEXT("Bad control object 0x%08x for comms device (id)"),
  1440. dwObject );
  1441. hres = DIERR_INVALIDPARAM;
  1442. }
  1443. }
  1444. else
  1445. {
  1446. SquirtSqflPtszV(sqflDf | sqflError,
  1447. TEXT("Comms control object 0x%08x not a button (id)"),
  1448. dwObject );
  1449. hres = DIERR_INVALIDPARAM;
  1450. }
  1451. }
  1452. else
  1453. {
  1454. AssertF( !"Physical genre not keyboard, mouse or voice (id)" );
  1455. }
  1456. return hres;
  1457. }
  1458. /*****************************************************************************
  1459. *
  1460. * @doc INTERNAL
  1461. *
  1462. * @func HRESULT | CMap_TestSysOffset |
  1463. *
  1464. * Test the passed offset to see if it is a reasonable one for the
  1465. * default data format of the physical genre.
  1466. *
  1467. * @parm DWORD | dwPhysicalGenre |
  1468. *
  1469. * Mouse, keyboard or voice as DIPHYSICAL_*
  1470. *
  1471. * @parm DWORD | dwOffset |
  1472. *
  1473. * The offset in question
  1474. *
  1475. * @returns
  1476. *
  1477. * <c S_OK> if the offset could be expected on the class of device
  1478. * or <c DIERR_INVALIDPARAM> if not
  1479. *
  1480. *****************************************************************************/
  1481. HRESULT CMap_TestSysOffset
  1482. (
  1483. DWORD dwPhysicalGenre,
  1484. DWORD dwOffset
  1485. )
  1486. {
  1487. HRESULT hres = S_OK;
  1488. if( dwPhysicalGenre == DIPHYSICAL_KEYBOARD )
  1489. {
  1490. /*
  1491. * Anything but a button with an 8 bit offset is invalid.
  1492. */
  1493. if( dwOffset <= 0xFF )
  1494. {
  1495. SquirtSqflPtszV(sqflDf | sqflBenign,
  1496. TEXT("Key 0x%02 not defined on this keyboard (ofs)"),
  1497. dwOffset );
  1498. }
  1499. else
  1500. {
  1501. SquirtSqflPtszV(sqflDf | sqflError,
  1502. TEXT("Key offset 0x%08 invalid for keyboard (ofs)"),
  1503. dwOffset );
  1504. hres = DIERR_INVALIDPARAM;
  1505. }
  1506. }
  1507. else if( dwPhysicalGenre == DIPHYSICAL_MOUSE )
  1508. {
  1509. CAssertF( DIMOFS_X == 0 );
  1510. if( dwOffset > DIMOFS_BUTTON7 )
  1511. {
  1512. SquirtSqflPtszV(sqflDf | sqflError,
  1513. TEXT("Bad control offset 0x%08x for mouse (ofs)"),
  1514. dwOffset );
  1515. hres = DIERR_INVALIDPARAM;
  1516. }
  1517. else
  1518. {
  1519. /*
  1520. * Allow buttons 1 to 8
  1521. */
  1522. if( dwOffset >= DIMOFS_BUTTON0 )
  1523. {
  1524. SquirtSqflPtszV(sqflDf | sqflBenign,
  1525. TEXT("Button %d not defined on this mouse (ofs)"),
  1526. dwOffset - DIMOFS_BUTTON0 );
  1527. }
  1528. else
  1529. {
  1530. SquirtSqflPtszV(sqflDf | sqflBenign,
  1531. TEXT("Axis %d not defined on this mouse (ofs)"),
  1532. (dwOffset - DIMOFS_X)>>2 );
  1533. }
  1534. }
  1535. }
  1536. else
  1537. {
  1538. AssertF( !"Physical genre not keyboard, mouse or voice" );
  1539. }
  1540. return hres;
  1541. }
  1542. /*****************************************************************************
  1543. *
  1544. * @doc INTERNAL
  1545. *
  1546. * @method HRESULT | CMap | DeviceValidateActionMap |
  1547. *
  1548. * Validate an action map for a device.
  1549. *
  1550. * @parm LPDIACTIONFORMATW | pActionFormat |
  1551. *
  1552. * Actions to map.
  1553. *
  1554. * @parm DWORD | dwDevGenre |
  1555. *
  1556. * Device genre to match or zero for device that are not physical
  1557. * devices.
  1558. *
  1559. * @parm REFGUID | guidInstace |
  1560. *
  1561. * Instance guid of device to match.
  1562. *
  1563. * @parm LPCDIDATAFORMAT | dfDev |
  1564. *
  1565. * Ponter to device data format.
  1566. *
  1567. * @parm DWORD | dwFlags |
  1568. *
  1569. * A valid combination of <c DVAM_*> flags to describe optional
  1570. * validation behavior.
  1571. *
  1572. * @returns
  1573. *
  1574. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  1575. *
  1576. *
  1577. *****************************************************************************/
  1578. #define DVAM_DEFAULT 0x00000000
  1579. #define DVAM_GETEXACTMAPPINGS 0x00000001
  1580. STDMETHODIMP
  1581. CMap_DeviceValidateActionMap
  1582. (
  1583. PV pdd,
  1584. LPDIACTIONFORMATW paf,
  1585. DWORD dwFlags,
  1586. PDWORD pdwOut
  1587. )
  1588. {
  1589. HRESULT hres;
  1590. LPDIDATAFORMAT dfDev;
  1591. DWORD dwPhysicalGenre;
  1592. LPDIACTIONW pAction;
  1593. PBYTE pMatch;
  1594. UINT idxObj;
  1595. BOOL bHasMap = FALSE;
  1596. BOOL bNewMap = FALSE;
  1597. DWORD dwCommsType = 0;
  1598. PDD this;
  1599. EnterProcI(IDirectInputDeviceCallback::CMap::DeviceValidateActionMap,
  1600. (_ "ppx", pdd, paf, dwFlags));
  1601. this = _thisPv(pdd);
  1602. /*
  1603. * Note, hres is tested before anything is done with dwPhysicalGenre
  1604. */
  1605. switch( GET_DIDEVICE_TYPE(this->dc3.dwDevType) )
  1606. {
  1607. case DI8DEVTYPE_MOUSE:
  1608. dwPhysicalGenre = DIPHYSICAL_MOUSE;
  1609. break;
  1610. case DI8DEVTYPE_KEYBOARD:
  1611. dwPhysicalGenre = DIPHYSICAL_KEYBOARD;
  1612. break;
  1613. case DI8DEVTYPE_DEVICECTRL:
  1614. if( ( GET_DIDEVICE_SUBTYPE( this->dc3.dwDevType ) == DI8DEVTYPEDEVICECTRL_COMMSSELECTION_HARDWIRED )
  1615. || ( GET_DIDEVICE_SUBTYPE( this->dc3.dwDevType ) == DI8DEVTYPEDEVICECTRL_COMMSSELECTION ) )
  1616. {
  1617. dwCommsType = GET_DIDEVICE_SUBTYPE( this->dc3.dwDevType );
  1618. dwPhysicalGenre = DIPHYSICAL_VOICE;
  1619. }
  1620. else
  1621. {
  1622. dwPhysicalGenre = 0;
  1623. }
  1624. break;
  1625. default:
  1626. dwPhysicalGenre = 0;
  1627. break;
  1628. }
  1629. if( SUCCEEDED( hres = this->pdcb->lpVtbl->GetDataFormat(this->pdcb, &dfDev) )
  1630. && SUCCEEDED( hres = AllocCbPpv( dfDev->dwNumObjs, &pMatch) ) )
  1631. {
  1632. enum eMap
  1633. {
  1634. eMapTestMatches,
  1635. eMapDeviceExact,
  1636. eMapClassExact,
  1637. eMapEnd
  1638. } iMap, ValidationLimit;
  1639. /*
  1640. * Set the limit on iterations depending on the checks required
  1641. */
  1642. ValidationLimit = ( dwFlags & DVAM_GETEXACTMAPPINGS )
  1643. ? ( dwPhysicalGenre ) ? eMapClassExact : eMapDeviceExact
  1644. : eMapTestMatches;
  1645. for( iMap = eMapTestMatches; SUCCEEDED( hres ) && ( iMap <= ValidationLimit ); iMap++ )
  1646. {
  1647. for( pAction = paf->rgoAction;
  1648. SUCCEEDED( hres ) && ( pAction < &paf->rgoAction[paf->dwNumActions] );
  1649. pAction++ )
  1650. {
  1651. DWORD dwObject;
  1652. if( pAction->dwFlags & DIA_APPNOMAP )
  1653. {
  1654. continue;
  1655. }
  1656. /*
  1657. * If we are mapping exact matches this time, only care
  1658. * about unmapped actions with app mappings.
  1659. */
  1660. if( ( iMap != eMapTestMatches )
  1661. && (!( pAction->dwFlags & DIA_APPMAPPED )
  1662. || ( pAction->dwHow & DIAH_MAPMASK ) ) )
  1663. {
  1664. continue;
  1665. }
  1666. switch( iMap )
  1667. {
  1668. case eMapTestMatches:
  1669. /*
  1670. * These flags have already been validated during semantic
  1671. * validation so just assert them on the first iteration.
  1672. */
  1673. AssertF( ( pAction->dwHow & ~DIAH_VALID ) == 0 );
  1674. AssertF( ( pAction->dwHow & DIAH_ERROR ) == 0 );
  1675. AssertF( ( pAction->dwFlags & ~DIA_VALID ) == 0 );
  1676. /*
  1677. * Only care about pre-existing matches
  1678. */
  1679. if( !( pAction->dwHow & DIAH_MAPMASK ) )
  1680. {
  1681. continue;
  1682. }
  1683. /*
  1684. * Fall through for a GUID match
  1685. */
  1686. case eMapDeviceExact:
  1687. if( !IsEqualGUID( &pAction->guidInstance, &this->guid ) )
  1688. {
  1689. continue;
  1690. }
  1691. break;
  1692. case eMapClassExact:
  1693. if( ( DISEM_GENRE_GET( pAction->dwSemantic ) != DISEM_GENRE_GET( dwPhysicalGenre ) ) )
  1694. {
  1695. continue;
  1696. }
  1697. break;
  1698. default:
  1699. AssertF( !"Invalid iMap" );
  1700. }
  1701. if( ( iMap != eMapTestMatches )
  1702. && ( dwCommsType == DI8DEVTYPEDEVICECTRL_COMMSSELECTION_HARDWIRED ) )
  1703. {
  1704. if( !( pAction->dwHow & DIAH_MAPMASK ) )
  1705. {
  1706. RPF( "ERROR: rgoAction[%d] is trying to map on a hardwired device", pAction - paf->rgoAction );
  1707. hres = DIERR_INVALIDPARAM;
  1708. }
  1709. else if( pAction->dwFlags & DIA_APPMAPPED )
  1710. {
  1711. RPF( "ERROR: rgoAction[%d] is trying to app map on a hardwired device", pAction - paf->rgoAction );
  1712. hres = DIERR_INVALIDPARAM;
  1713. }
  1714. }
  1715. else
  1716. {
  1717. dwObject = pAction->dwObjID;
  1718. /*
  1719. * Now try to find the object.
  1720. * Note, we can't rely on the application data format goo
  1721. * because a data format has probably not been set.
  1722. */
  1723. for( idxObj = 0; idxObj < dfDev->dwNumObjs; idxObj++ )
  1724. {
  1725. /*
  1726. * Ignore FF flags so a FF device can be matched for non-FF
  1727. */
  1728. if( ( ( dwObject ^ dfDev->rgodf[idxObj].dwType )
  1729. &~( DIDFT_FFACTUATOR | DIDFT_FFEFFECTTRIGGER ) ) == 0 )
  1730. {
  1731. break;
  1732. }
  1733. }
  1734. if( idxObj < dfDev->dwNumObjs )
  1735. {
  1736. /*
  1737. * Application mapped controls don't need to have
  1738. * semantics so we cannot test them.
  1739. */
  1740. if( pAction->dwFlags & DIA_APPMAPPED )
  1741. {
  1742. if( pMatch[idxObj] )
  1743. {
  1744. RPF( "ERROR: rgoAction[%d] maps to control 0x%08x which is already mapped",
  1745. pAction - paf->rgoAction, pAction->dwObjID );
  1746. hres = DIERR_INVALIDPARAM;
  1747. break;
  1748. }
  1749. else
  1750. {
  1751. if(!( pAction->dwFlags & DIA_FORCEFEEDBACK )
  1752. || ( dfDev->rgodf[idxObj].dwType & ( DIDFT_FFACTUATOR | DIDFT_FFEFFECTTRIGGER ) ) )
  1753. {
  1754. pMatch[idxObj] = TRUE;
  1755. SquirtSqflPtszV(sqflDf | sqflVerbose,
  1756. TEXT("rgoAction[%d] application mapped to object 0x%08x"),
  1757. pAction - paf->rgoAction, dwObject );
  1758. bHasMap = TRUE;
  1759. if( iMap != eMapTestMatches )
  1760. {
  1761. bNewMap = TRUE;
  1762. pAction->dwHow = DIAH_APPREQUESTED;
  1763. pAction->dwObjID = dwObject;
  1764. if( iMap == eMapClassExact )
  1765. {
  1766. pAction->guidInstance = this->guid;
  1767. }
  1768. }
  1769. }
  1770. else
  1771. {
  1772. RPF( "ERROR: rgoAction[%d] need force feedback but object 0x%08x has none",
  1773. pAction - paf->rgoAction, dwObject );
  1774. hres = DIERR_INVALIDPARAM;
  1775. break;
  1776. }
  1777. }
  1778. }
  1779. else
  1780. {
  1781. AssertF( iMap == eMapTestMatches );
  1782. /*
  1783. * Check the object type matches the semantic
  1784. */
  1785. if( ( c_SemTypeToDFType[ DISEM_TYPEANDMODE_GET( pAction->dwSemantic ) ]
  1786. & DIDFT_GETTYPE( dwObject ) ) )
  1787. {
  1788. if( pMatch[idxObj] )
  1789. {
  1790. RPF( "ERROR: rgoAction[%d] pre-mapped to control 0x%08x which is already mapped",
  1791. pAction - paf->rgoAction, pAction->dwObjID );
  1792. hres = DIERR_INVALIDPARAM;
  1793. break;
  1794. }
  1795. else
  1796. {
  1797. pMatch[idxObj] = TRUE;
  1798. bHasMap = TRUE;
  1799. SquirtSqflPtszV(sqflDf | sqflVerbose,
  1800. TEXT("rgoAction[%d] mapping verifed to object 0x%08x"),
  1801. pAction - paf->rgoAction, dwObject );
  1802. continue;
  1803. }
  1804. }
  1805. else
  1806. {
  1807. RPF( "ERROR: rgoAction[%d] has object type 0x%08x but semantic type 0x%08x",
  1808. pAction - paf->rgoAction, DIDFT_GETTYPE( dwObject ),
  1809. c_SemTypeToDFType[ DISEM_TYPEANDMODE_GET( pAction->dwSemantic ) ] );
  1810. hres = DIERR_INVALIDPARAM;
  1811. break;
  1812. }
  1813. }
  1814. }
  1815. else
  1816. {
  1817. switch( iMap )
  1818. {
  1819. case eMapTestMatches:
  1820. RPF( "ERROR: rgoAction[%d] was mapped (how:0x%08x) to undefined object 0x%08x",
  1821. pAction - paf->rgoAction, pAction->dwHow, pAction->dwObjID );
  1822. hres = DIERR_INVALIDPARAM;
  1823. break;
  1824. case eMapDeviceExact:
  1825. RPF( "ERROR: rgoAction[%d] has application map to undefined object 0x%08x",
  1826. pAction - paf->rgoAction, pAction->dwObjID );
  1827. hres = DIERR_INVALIDPARAM;
  1828. break;
  1829. case eMapClassExact:
  1830. /*
  1831. * If a device class was specified and no match was
  1832. * found it is only an error if the object is
  1833. * invalid for the class.
  1834. */
  1835. hres = CMap_TestSysObject( dwPhysicalGenre, pAction->dwObjID );
  1836. if( FAILED( hres ) )
  1837. {
  1838. RPF( "ERROR: rgoAction[%d] was mapped to object 0x%08x, not valid for device",
  1839. pAction - paf->rgoAction, pAction->dwObjID );
  1840. }
  1841. else
  1842. {
  1843. continue; /* Don't break the loop */
  1844. }
  1845. }
  1846. break;
  1847. }
  1848. }
  1849. }
  1850. if( FAILED( hres ) )
  1851. {
  1852. pAction->dwHow = DIAH_ERROR;
  1853. AssertF( hres == DIERR_INVALIDPARAM );
  1854. break;
  1855. }
  1856. }
  1857. FreePv( pMatch );
  1858. }
  1859. if( SUCCEEDED( hres ) )
  1860. {
  1861. AssertF( hres == S_OK );
  1862. if( dwCommsType == DI8DEVTYPEDEVICECTRL_COMMSSELECTION_HARDWIRED )
  1863. {
  1864. hres = DI_WRITEPROTECT;
  1865. }
  1866. else if(dwFlags == DVAM_DEFAULT)
  1867. {
  1868. //in default case we want to know if there are ANY mappings
  1869. if (!bHasMap)
  1870. hres = DI_NOEFFECT;
  1871. }
  1872. else if(!bNewMap)
  1873. {
  1874. //in non-default case we are interested in ANY NEW mappings
  1875. hres = DI_NOEFFECT;
  1876. }
  1877. }
  1878. *pdwOut = dwCommsType;
  1879. ExitOleProcR();
  1880. return hres;
  1881. }
  1882. /*****************************************************************************
  1883. *
  1884. * @doc INTERNAL
  1885. *
  1886. * @method HRESULT | CMap | BuildDefaultDevActionMap |
  1887. *
  1888. * Get default action map from the action format non system devices.
  1889. *
  1890. * @parm LPDIACTIONFORMATW | pActionFormat |
  1891. *
  1892. * Actions to map.
  1893. *
  1894. * @parm DWORD | dwFlags |
  1895. *
  1896. * Flags used to indicate mapping preferences.
  1897. *
  1898. * @parm REFGUID | guidInstace |
  1899. *
  1900. * Instance guid of device to match.
  1901. *
  1902. * @parm PDIDOBJDEFSEM | rgObjSem |
  1903. *
  1904. * Array of default device object to semantic mappings.
  1905. *
  1906. * @parm DWORD | dwNumAxes |
  1907. *
  1908. * Number of axes in the rgObjSem.
  1909. *
  1910. * @parm DWORD | dwNumPOVs |
  1911. *
  1912. * Number of POVs in the rgObjSem.
  1913. *
  1914. * @parm DWORD | dwNumAxes |
  1915. *
  1916. * Number of buttons in the rgObjSem.
  1917. *
  1918. * @returns
  1919. *
  1920. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  1921. *
  1922. *
  1923. *****************************************************************************/
  1924. STDMETHODIMP CMap_BuildDefaultDevActionMap
  1925. (
  1926. LPDIACTIONFORMATW paf,
  1927. DWORD dwFlags,
  1928. REFGUID guidDevInst,
  1929. PDIDOBJDEFSEM rgObjSem,
  1930. DWORD dwNumAxes,
  1931. DWORD dwNumPOVs,
  1932. DWORD dwNumButtons
  1933. )
  1934. {
  1935. #define IS_OBJECT_USED( dwSem ) ( DISEM_RES_GET( dwSem ) )
  1936. #define MARK_OBJECT_AS_USED( dwSem ) ( dwSem |= DISEM_RES_SET( 1 ) )
  1937. HRESULT hres = S_OK;
  1938. BOOL fSomethingMapped = FALSE;
  1939. PDIDOBJDEFSEM pSemNextPOV;
  1940. PDIDOBJDEFSEM pSemButtons;
  1941. LPDIACTIONW pAction;
  1942. enum eMap
  1943. {
  1944. eMapDeviceSemantic,
  1945. eMapDeviceCompat,
  1946. eMapGenericSemantic,
  1947. eMapGenericCompat,
  1948. eMapEnd
  1949. } iMap;
  1950. EnterProcI(IDirectInputDeviceCallback::CMap::BuildDefaultDevActionMap,
  1951. (_ "pxGpxxx", paf, dwFlags, guidDevInst,
  1952. rgObjSem, dwNumAxes, dwNumPOVs, dwNumButtons ));
  1953. pSemNextPOV = &rgObjSem[dwNumAxes];
  1954. pSemButtons = &rgObjSem[dwNumAxes+dwNumPOVs];
  1955. /*
  1956. * Make an initial pass through to mark already mapped actions
  1957. */
  1958. for( pAction = paf->rgoAction; pAction < &paf->rgoAction[paf->dwNumActions]; pAction++ )
  1959. {
  1960. PDIDOBJDEFSEM pSemExact;
  1961. /*
  1962. * These flags have already been validated during semantic validation,
  1963. */
  1964. AssertF( ( pAction->dwHow & ~DIAH_VALID ) == 0 );
  1965. AssertF( ( pAction->dwHow & DIAH_ERROR ) == 0 );
  1966. AssertF( ( pAction->dwFlags & ~DIA_VALID ) == 0 );
  1967. if( ( pAction->dwFlags & DIA_APPNOMAP )
  1968. ||!( pAction->dwHow & DIAH_MAPMASK )
  1969. ||!IsEqualGUID( &pAction->guidInstance, guidDevInst ) )
  1970. {
  1971. continue;
  1972. }
  1973. /*
  1974. * This object has already been validated so mark it as
  1975. * in use so we don't try to reuse it.
  1976. * No errors should be detected here so use asserts not retail tests
  1977. */
  1978. AssertF( pAction->dwObjID != 0xFFFFFFFF );
  1979. /*
  1980. * Find the object
  1981. */
  1982. for( pSemExact = rgObjSem;
  1983. pSemExact < &rgObjSem[dwNumAxes+dwNumPOVs+dwNumButtons];
  1984. pSemExact++ )
  1985. {
  1986. if( ( ( pSemExact->dwID ^ pAction->dwObjID )
  1987. &~( DIDFT_FFACTUATOR | DIDFT_FFEFFECTTRIGGER ) ) == 0 )
  1988. {
  1989. AssertF( !IS_OBJECT_USED( pSemExact->dwSemantic ) );
  1990. AssertF( DISEM_TYPE_GET( pAction->dwSemantic )
  1991. == DISEM_TYPE_GET( pSemExact->dwSemantic ) );
  1992. MARK_OBJECT_AS_USED( pSemExact->dwSemantic );
  1993. break;
  1994. }
  1995. }
  1996. /*
  1997. * ISSUE-2001/03/29-timgill There should always be an exact action match
  1998. * May need to use tests for duplicates and unmatched controls
  1999. */
  2000. AssertF( pSemExact < &rgObjSem[dwNumAxes+dwNumPOVs+dwNumButtons] );
  2001. }
  2002. for( iMap=0; iMap<eMapEnd; iMap++ )
  2003. {
  2004. for( pAction = paf->rgoAction; pAction < &paf->rgoAction[paf->dwNumActions]; pAction++ )
  2005. {
  2006. /*
  2007. * Do trivial tests first
  2008. */
  2009. if( pAction->dwHow & DIAH_MAPMASK )
  2010. {
  2011. continue;
  2012. }
  2013. if( pAction->dwFlags & DIA_APPNOMAP )
  2014. {
  2015. continue;
  2016. }
  2017. switch( iMap )
  2018. {
  2019. case eMapDeviceSemantic:
  2020. case eMapGenericSemantic:
  2021. if( DISEM_GENRE_GET( pAction->dwSemantic ) == DISEM_GENRE_GET( DISEMGENRE_ANY ) )
  2022. {
  2023. continue; /* No semantic mapping requested */
  2024. }
  2025. if( ( DISEM_TYPE_GET( pAction->dwSemantic ) == DISEM_TYPE_GET( DISEM_TYPE_BUTTON ) )
  2026. && ( DISEM_FLAGS_GET( pAction->dwSemantic ) != 0 ) )
  2027. {
  2028. continue; /* Don't touch link buttons now */
  2029. }
  2030. break;
  2031. case eMapDeviceCompat:
  2032. case eMapGenericCompat:
  2033. if( ( DISEM_GENRE_GET( pAction->dwSemantic ) != DISEM_GENRE_GET( DISEMGENRE_ANY ) )
  2034. && ( DISEM_TYPE_GET( pAction->dwSemantic ) == DISEM_TYPE_GET( DISEM_TYPE_AXIS ) ) )
  2035. {
  2036. continue; /* No generic mapping requested or taken by default */
  2037. }
  2038. break;
  2039. }
  2040. /*
  2041. * Next test that this device suits this action (for this pass)
  2042. */
  2043. if( iMap <= eMapDeviceCompat )
  2044. {
  2045. if( !IsEqualGUID( &pAction->guidInstance, guidDevInst ) )
  2046. {
  2047. continue;
  2048. }
  2049. }
  2050. else if( !IsEqualGUID( &pAction->guidInstance, &GUID_Null) )
  2051. {
  2052. continue;
  2053. }
  2054. else if( ( DISEM_GENRE_GET( pAction->dwSemantic ) == DISEM_GENRE_GET( DIPHYSICAL_MOUSE ) )
  2055. || ( DISEM_GENRE_GET( pAction->dwSemantic ) == DISEM_GENRE_GET( DIPHYSICAL_KEYBOARD ) )
  2056. || ( DISEM_GENRE_GET( pAction->dwSemantic ) == DISEM_GENRE_GET( DIPHYSICAL_VOICE ) ) )
  2057. {
  2058. continue;
  2059. }
  2060. /*
  2061. * Only actions which may be matched on this device get this far.
  2062. */
  2063. switch( iMap )
  2064. {
  2065. case eMapDeviceSemantic:
  2066. case eMapGenericSemantic:
  2067. /*
  2068. * See if a matching control is available.
  2069. */
  2070. switch( DISEM_TYPE_GET( pAction->dwSemantic ) )
  2071. {
  2072. case DISEM_TYPE_GET( DISEM_TYPE_AXIS ):
  2073. {
  2074. DWORD dwAxisType = DISEM_FLAGS_GET( pAction->dwSemantic );
  2075. DWORD dwSemObjType;
  2076. UINT uAxisIdx;
  2077. /*
  2078. * Set up a mask of the type of object we need to find
  2079. */
  2080. dwSemObjType = c_SemTypeToDFType[ DISEM_TYPEANDMODE_GET( pAction->dwSemantic ) ];
  2081. if( pAction->dwFlags & DIA_FORCEFEEDBACK )
  2082. {
  2083. dwSemObjType |= DIDFT_FFACTUATOR;
  2084. }
  2085. for( uAxisIdx = 0; uAxisIdx < dwNumAxes; uAxisIdx++ )
  2086. {
  2087. if( ( dwAxisType == DISEM_FLAGS_GET( rgObjSem[uAxisIdx].dwSemantic ) )
  2088. && ( ( dwSemObjType & rgObjSem[uAxisIdx].dwID ) == dwSemObjType )
  2089. && ( !IS_OBJECT_USED( rgObjSem[uAxisIdx].dwSemantic ) ) )
  2090. {
  2091. pAction->dwObjID = rgObjSem[uAxisIdx].dwID;
  2092. MARK_OBJECT_AS_USED( rgObjSem[uAxisIdx].dwSemantic );
  2093. break;
  2094. }
  2095. }
  2096. if( uAxisIdx >= dwNumAxes )
  2097. {
  2098. continue; /* No matching left */
  2099. }
  2100. break;
  2101. }
  2102. case DISEM_TYPE_GET( DISEM_TYPE_POV ):
  2103. /*
  2104. * Note, no control of POV ordering
  2105. */
  2106. if( ( pSemNextPOV < pSemButtons )
  2107. &&!( pAction->dwFlags & DIA_FORCEFEEDBACK ) )
  2108. {
  2109. pAction->dwObjID = pSemNextPOV->dwID;
  2110. MARK_OBJECT_AS_USED( pSemNextPOV->dwSemantic );
  2111. pSemNextPOV++;
  2112. }
  2113. else
  2114. {
  2115. if( pAction->dwFlags & DIA_FORCEFEEDBACK )
  2116. {
  2117. SquirtSqflPtszV(sqflDf | sqflBenign,
  2118. TEXT( "Not mapping force feedback semantic hat switch (huh?), rgoAction[%d]"),
  2119. pAction - paf->rgoAction );
  2120. }
  2121. continue; /* None left */
  2122. }
  2123. break;
  2124. case DISEM_TYPE_GET( DISEM_TYPE_BUTTON ):
  2125. {
  2126. DWORD dwButtonIdx;
  2127. dwButtonIdx = DISEM_INDEX_GET( pAction->dwSemantic );
  2128. if( dwButtonIdx >= DIAS_INDEX_SPECIAL )
  2129. {
  2130. /*
  2131. * 0xFF used to mean DIBUTTON_ANY.
  2132. * To avoid changing other special indices, still
  2133. * use 0xFF as the base number.
  2134. */
  2135. dwButtonIdx = dwNumButtons - ( 0xFF - dwButtonIdx );
  2136. }
  2137. else
  2138. {
  2139. dwButtonIdx--;
  2140. }
  2141. if( ( dwButtonIdx >= dwNumButtons )
  2142. || ( IS_OBJECT_USED( pSemButtons[dwButtonIdx].dwSemantic ) )
  2143. || ( ( pAction->dwFlags & DIA_FORCEFEEDBACK )
  2144. &&!( pSemButtons[dwButtonIdx].dwID & DIDFT_FFEFFECTTRIGGER ) ) )
  2145. {
  2146. continue; /* No match, no harm */
  2147. }
  2148. else
  2149. {
  2150. pAction->dwObjID = pSemButtons[dwButtonIdx].dwID;
  2151. MARK_OBJECT_AS_USED( pSemButtons[dwButtonIdx].dwSemantic );
  2152. }
  2153. break;
  2154. }
  2155. default:
  2156. RPF( "ERROR Invalid action: rgoAction[%d].dwSemantic 0x%08x",
  2157. pAction - paf->rgoAction, pAction->dwSemantic );
  2158. pAction->dwHow = DIAH_ERROR;
  2159. hres = DIERR_INVALIDPARAM;
  2160. goto error_exit;
  2161. }
  2162. pAction->dwHow = DIAH_DEFAULT;
  2163. break;
  2164. case eMapDeviceCompat:
  2165. case eMapGenericCompat:
  2166. if( ( DISEM_TYPE_GET( pAction->dwSemantic ) == DISEM_TYPE_GET( DISEM_TYPE_BUTTON ) )
  2167. && ( DISEM_FLAGS_GET( pAction->dwSemantic ) != 0 ) )
  2168. {
  2169. LPDIACTIONW pActionTest;
  2170. PDIDOBJDEFSEM pSemTest;
  2171. DWORD dwSemMask;
  2172. /*
  2173. * See if the axis or POV has been mapped
  2174. * Note, there may be no linked object
  2175. */
  2176. if( ( pAction->dwSemantic & DISEM_FLAGS_MASK ) == DISEM_FLAGS_P )
  2177. {
  2178. dwSemMask = DISEM_GROUP_MASK;
  2179. }
  2180. else
  2181. {
  2182. dwSemMask = ( DISEM_FLAGS_MASK | DISEM_GROUP_MASK );
  2183. }
  2184. for( pActionTest = paf->rgoAction; pActionTest < &paf->rgoAction[paf->dwNumActions]; pActionTest++ )
  2185. {
  2186. /*
  2187. * Find the axis or POV for which this button is a fallback
  2188. * Ignore buttons as they are just other fallbacks for the same action
  2189. * Don't do fallbacks for ANY* axes or POVs.
  2190. */
  2191. if( ( DISEM_TYPE_GET( pActionTest->dwSemantic ) != DISEM_TYPE_GET( DISEM_TYPE_BUTTON ) )
  2192. && ( DISEM_GENRE_GET( pAction->dwSemantic ) != DISEM_GENRE_GET( DISEMGENRE_ANY ) )
  2193. && ( ( ( pActionTest->dwSemantic ^ pAction->dwSemantic ) & dwSemMask ) == 0 ) )
  2194. {
  2195. break;
  2196. }
  2197. }
  2198. if( ( pActionTest < &paf->rgoAction[paf->dwNumActions] )
  2199. && ( pActionTest->dwHow & DIAH_MAPMASK ) )
  2200. {
  2201. continue; /* Don't need a fallback */
  2202. }
  2203. /*
  2204. * Find a button
  2205. */
  2206. for( pSemTest = pSemButtons; pSemTest < &pSemButtons[dwNumButtons]; pSemTest++ )
  2207. {
  2208. if( !IS_OBJECT_USED( pSemTest->dwSemantic ) )
  2209. {
  2210. if( ( pAction->dwFlags & DIA_FORCEFEEDBACK )
  2211. &&!( pSemTest->dwID & DIDFT_FFEFFECTTRIGGER ) )
  2212. {
  2213. continue;
  2214. }
  2215. pAction->dwObjID = pSemTest->dwID;
  2216. MARK_OBJECT_AS_USED( pSemTest->dwSemantic );
  2217. break;
  2218. }
  2219. }
  2220. if( pSemTest == &pSemButtons[dwNumButtons] )
  2221. {
  2222. continue; /* None left */
  2223. }
  2224. pAction->dwHow = DIAH_DEFAULT;
  2225. }
  2226. else
  2227. {
  2228. PDIDOBJDEFSEM pSemTest;
  2229. PDIDOBJDEFSEM pSemBound;
  2230. int iDirection = 1;
  2231. DWORD dwSemObjType;
  2232. /*
  2233. * Set up a mask of the type of object we need to find to
  2234. * filter out axes of the wrong mode and non-FF if needed
  2235. */
  2236. dwSemObjType = c_SemTypeToDFType[ DISEM_TYPEANDMODE_GET( pAction->dwSemantic ) ];
  2237. if( pAction->dwFlags & DIA_FORCEFEEDBACK )
  2238. {
  2239. dwSemObjType |= DIDFT_FFACTUATOR | DIDFT_FFEFFECTTRIGGER;
  2240. }
  2241. /*
  2242. * Search the available controls for a match
  2243. */
  2244. switch( DISEM_TYPE_GET( pAction->dwSemantic ) )
  2245. {
  2246. case DISEM_TYPE_GET( DISEM_TYPE_AXIS ):
  2247. pSemTest = rgObjSem;
  2248. pSemBound = &rgObjSem[dwNumAxes];
  2249. /*
  2250. * Filter out axes of the wrong mode and FF caps
  2251. */
  2252. dwSemObjType &= DIDFT_FFACTUATOR | DIDFT_AXIS;
  2253. break;
  2254. case DISEM_TYPE_GET( DISEM_TYPE_POV ):
  2255. if( pAction->dwFlags & DIA_FORCEFEEDBACK )
  2256. {
  2257. SquirtSqflPtszV(sqflDf | sqflBenign,
  2258. TEXT( "Not mapping force feedback compatible hat switch (huh?), rgoAction[%d]"),
  2259. pAction - paf->rgoAction );
  2260. continue;
  2261. }
  2262. pSemTest = pSemNextPOV;
  2263. pSemBound = pSemButtons;
  2264. /*
  2265. * Don't filter POVs any more
  2266. */
  2267. dwSemObjType = 0;
  2268. break;
  2269. case DISEM_TYPE_GET( DISEM_TYPE_BUTTON ):
  2270. /*
  2271. * Note a DIBUTTON_ANY with instance DIAS_INDEX_SPECIAL
  2272. * or greater can be mapped from the end.
  2273. */
  2274. if( DISEM_INDEX_GET( pAction->dwSemantic ) >= DIAS_INDEX_SPECIAL )
  2275. {
  2276. /*
  2277. * For buttons selected from the end, find the last available
  2278. */
  2279. iDirection = -1;
  2280. pSemTest = &rgObjSem[dwNumAxes + dwNumPOVs + dwNumButtons - 1];
  2281. pSemBound = pSemButtons - 1;
  2282. }
  2283. else
  2284. {
  2285. pSemTest = pSemButtons;
  2286. pSemBound = &rgObjSem[dwNumAxes + dwNumPOVs + dwNumButtons];
  2287. }
  2288. /*
  2289. * Filter triggers but just in case, do not distinguish
  2290. * between types of buttons (toggle/push).
  2291. */
  2292. dwSemObjType &= DIDFT_FFEFFECTTRIGGER;
  2293. break;
  2294. }
  2295. while( pSemTest != pSemBound )
  2296. {
  2297. if( !IS_OBJECT_USED( pSemTest->dwSemantic )
  2298. && ( ( dwSemObjType & pSemTest->dwID ) == dwSemObjType )
  2299. && ( ( DISEM_FLAGS_GET( pAction->dwSemantic ) == 0 )
  2300. ||( DISEM_FLAGS_GET( pAction->dwSemantic ) == DISEM_FLAGS_GET( pSemTest->dwSemantic ) ) ) )
  2301. {
  2302. pAction->dwObjID = pSemTest->dwID;
  2303. MARK_OBJECT_AS_USED( pSemTest->dwSemantic );
  2304. break;
  2305. }
  2306. pSemTest += iDirection;
  2307. }
  2308. if( pSemTest == pSemBound )
  2309. {
  2310. continue; /* None left */
  2311. }
  2312. pAction->dwHow = DIAH_DEFAULT;
  2313. }
  2314. break;
  2315. #ifdef XDEBUG
  2316. default:
  2317. AssertF(0);
  2318. #endif
  2319. }
  2320. SquirtSqflPtszV(sqflDf | sqflVerbose,
  2321. TEXT( "Match for action %d is object 0x%08x and how 0x%08x"),
  2322. pAction - paf->rgoAction, pAction->dwObjID, pAction->dwHow );
  2323. /*
  2324. * If we get this far, we have a match.
  2325. * The control object id and dwHow field should have been set
  2326. */
  2327. AssertF( ( pAction->dwHow == DIAH_DEFAULT ) || ( pAction->dwHow == DIAH_APPREQUESTED ) );
  2328. pAction->guidInstance = *guidDevInst;
  2329. SquirtSqflPtszV(sqflDf | sqflVerbose,
  2330. TEXT("Action %d mapped to object id 0x%08x"),
  2331. pAction - paf->rgoAction, pAction->dwObjID );
  2332. fSomethingMapped = TRUE;
  2333. } /* Action loop */
  2334. } /* Match loop */
  2335. /*
  2336. * The result should always be S_OK
  2337. */
  2338. AssertF( hres == S_OK );
  2339. /*
  2340. * If nothing was mapped, let the caller know
  2341. */
  2342. if( !fSomethingMapped )
  2343. {
  2344. hres = DI_NOEFFECT;
  2345. }
  2346. error_exit:;
  2347. ExitOleProc();
  2348. return hres;
  2349. #undef IS_OBJECT_USED
  2350. #undef MARK_OBJECT_AS_USED
  2351. }
  2352. /*****************************************************************************
  2353. *
  2354. * @doc INTERNAL
  2355. *
  2356. * @method HRESULT | CMap | BuildDefaultSysActionMap |
  2357. *
  2358. * Build default action map from the action format for mouse or
  2359. * keyboard devices.
  2360. *
  2361. * @parm LPDIACTIONFORMATW | paf |
  2362. *
  2363. * Actions to map.
  2364. *
  2365. * @parm DWORD | dwFlags |
  2366. *
  2367. * Flags used to indicate mapping preferences.
  2368. *
  2369. * @parm DWORD | dwPhysicalGenre |
  2370. *
  2371. * Device genre to match.
  2372. *
  2373. * @parm REFGUID | guidDevInst |
  2374. *
  2375. * Instance guid of device to match.
  2376. *
  2377. * @parm LPDIDATAFORMAT | dfDev |
  2378. *
  2379. * Internal data format of device.
  2380. *
  2381. * @parm DWORD | dwButtonZeroInst |
  2382. *
  2383. * For mice only, the instance number of the first button.
  2384. *
  2385. * @returns
  2386. *
  2387. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  2388. *
  2389. *
  2390. *****************************************************************************/
  2391. STDMETHODIMP
  2392. CMap_BuildDefaultSysActionMap
  2393. (
  2394. LPDIACTIONFORMATW paf,
  2395. DWORD dwFlags,
  2396. DWORD dwPhysicalGenre,
  2397. REFGUID guidDevInst,
  2398. LPDIDATAFORMAT dfDev,
  2399. DWORD dwButtonZeroInst
  2400. )
  2401. {
  2402. HRESULT hres;
  2403. PBYTE pMatch;
  2404. UINT idxAxis;
  2405. UINT idxButton;
  2406. EnterProcI(IDirectInputDeviceCallback::CMap::BuildDefaultSysActionMap,
  2407. (_ "pxxGpu", paf, dwFlags, dwPhysicalGenre, guidDevInst, dfDev, dwButtonZeroInst ));
  2408. idxButton = 0;
  2409. if( dwPhysicalGenre == DIPHYSICAL_KEYBOARD )
  2410. {
  2411. idxAxis = dfDev->dwNumObjs;
  2412. }
  2413. else
  2414. {
  2415. idxAxis = 0;
  2416. AssertF( dwPhysicalGenre == DIPHYSICAL_MOUSE );
  2417. }
  2418. if( SUCCEEDED( hres = AllocCbPpv( dfDev->dwNumObjs, &pMatch) ) )
  2419. {
  2420. BOOL fSomethingMapped = FALSE;
  2421. enum eMap
  2422. {
  2423. eMapPrevious,
  2424. eMapDeviceSemantic,
  2425. eMapClassSemantic,
  2426. eMapEnd
  2427. } iMap;
  2428. for( iMap=0; iMap<eMapEnd; iMap++ )
  2429. {
  2430. LPDIACTIONW pAction;
  2431. for( pAction = paf->rgoAction; pAction < &paf->rgoAction[paf->dwNumActions]; pAction++ )
  2432. {
  2433. DWORD dwObject;
  2434. UINT idxObj;
  2435. dwObject = (DWORD)-1;
  2436. /*
  2437. * These flags have already been validated during semantic validation,
  2438. */
  2439. AssertF( ( pAction->dwHow & ~DIAH_VALID ) == 0 );
  2440. AssertF( ( pAction->dwHow & DIAH_ERROR ) == 0 );
  2441. AssertF( ( pAction->dwFlags & ~DIA_VALID ) == 0 );
  2442. if( pAction->dwFlags & DIA_APPNOMAP )
  2443. {
  2444. continue;
  2445. }
  2446. if( iMap == eMapPrevious )
  2447. {
  2448. if( !( pAction->dwHow & DIAH_MAPMASK ) )
  2449. {
  2450. continue;
  2451. }
  2452. }
  2453. else
  2454. {
  2455. if( pAction->dwHow & DIAH_MAPMASK )
  2456. {
  2457. continue;
  2458. }
  2459. }
  2460. if( iMap < eMapClassSemantic )
  2461. {
  2462. if( !IsEqualGUID( &pAction->guidInstance, guidDevInst ) )
  2463. {
  2464. continue;
  2465. }
  2466. /*
  2467. * Check that the physical genre is compatible with this device
  2468. */
  2469. if( DISEM_GENRE_GET( pAction->dwSemantic ) != DISEM_GENRE_GET( dwPhysicalGenre ) )
  2470. {
  2471. SquirtSqflPtszV(sqflDf | sqflError,
  2472. TEXT("Device specified for action does not match physical genre"));
  2473. break;
  2474. }
  2475. }
  2476. else
  2477. if( !IsEqualGUID( &pAction->guidInstance, &GUID_Null)
  2478. || ( DISEM_GENRE_GET( pAction->dwSemantic ) != DISEM_GENRE_GET( dwPhysicalGenre ) ) )
  2479. {
  2480. continue;
  2481. }
  2482. if( iMap == eMapPrevious )
  2483. {
  2484. /*
  2485. * This match has already been validated
  2486. */
  2487. SquirtSqflPtszV(sqflDf | sqflVerbose,
  2488. TEXT("Action %d already mapped by 0x%08x to object 0x%08x"),
  2489. pAction - paf->rgoAction, pAction->dwHow, pAction->dwObjID );
  2490. AssertF( pAction->dwObjID != 0xFFFFFFFF );
  2491. /*
  2492. * Find the object index
  2493. */
  2494. for( idxObj = 0; idxObj < dfDev->dwNumObjs; idxObj++ )
  2495. {
  2496. if( ( dfDev->rgodf[idxObj].dwType & DIDFT_FINDMASK ) == ( pAction->dwObjID & DIDFT_FINDMASK ) )
  2497. {
  2498. break;
  2499. }
  2500. }
  2501. if( idxObj < dfDev->dwNumObjs )
  2502. {
  2503. /*
  2504. * Validation should have caught duplicates
  2505. */
  2506. AssertF( !pMatch[idxObj] );
  2507. pMatch[idxObj] = TRUE;
  2508. /*
  2509. * Nothing else to do since we're just counting previous matches
  2510. */
  2511. continue;
  2512. }
  2513. else
  2514. {
  2515. SquirtSqflPtszV(sqflDf | sqflError,
  2516. TEXT("Action %d previously mapped by 0x%08x to unknown object 0x%08x"),
  2517. pAction - paf->rgoAction, pAction->dwHow, pAction->dwObjID );
  2518. }
  2519. }
  2520. else
  2521. {
  2522. DWORD dwSemObjType = c_SemTypeToDFType[ DISEM_TYPEANDMODE_GET( pAction->dwSemantic ) ];
  2523. AssertF( ( iMap == eMapDeviceSemantic ) || ( iMap == eMapClassSemantic ) );
  2524. /*
  2525. * System devices have index of the semantic = object default offset
  2526. * use that to find the object index
  2527. */
  2528. for( idxObj = 0; idxObj < dfDev->dwNumObjs; idxObj++ )
  2529. {
  2530. /*
  2531. * Test that this is an appropriate input type.
  2532. */
  2533. if(!( dfDev->rgodf[idxObj].dwType & dwSemObjType )
  2534. || ( dfDev->rgodf[idxObj].dwType & DIDFT_NODATA ) )
  2535. {
  2536. continue;
  2537. }
  2538. /*
  2539. * All keyboards currently use the same (default)
  2540. * data format so the index can be used directly
  2541. * to match the semantic.
  2542. */
  2543. if( dwPhysicalGenre == DIPHYSICAL_KEYBOARD )
  2544. {
  2545. if( dfDev->rgodf[idxObj].dwOfs != DISEM_INDEX_GET( pAction->dwSemantic ) )
  2546. {
  2547. continue;
  2548. }
  2549. }
  2550. else
  2551. {
  2552. /*
  2553. * Mice are more awkward as HID mice data
  2554. * formats depend on the device so use the
  2555. * dwType instead.
  2556. */
  2557. if( dwSemObjType & DIDFT_BUTTON )
  2558. {
  2559. /*
  2560. * A matching button is offset by the
  2561. * caller supplied button zero instance as
  2562. * the default button zero is instance 3.
  2563. */
  2564. if( DIDFT_GETINSTANCE( dfDev->rgodf[idxObj].dwType ) - (BYTE)dwButtonZeroInst
  2565. != DISEM_INDEX_GET( pAction->dwSemantic ) - DIMOFS_BUTTON0 )
  2566. {
  2567. continue;
  2568. }
  2569. }
  2570. else
  2571. {
  2572. /*
  2573. * All mice have axis instances: x=0, y=1, z=2
  2574. */
  2575. AssertF( dwSemObjType & DIDFT_AXIS );
  2576. if( ( DIDFT_GETINSTANCE( dfDev->rgodf[idxObj].dwType ) << 2 )
  2577. != DISEM_INDEX_GET( pAction->dwSemantic ) )
  2578. {
  2579. continue;
  2580. }
  2581. }
  2582. }
  2583. /*
  2584. * A semantic match has been found
  2585. */
  2586. if( pMatch[idxObj] )
  2587. {
  2588. SquirtSqflPtszV(sqflDf | sqflError,
  2589. TEXT("Action %d maps to already mapped object 0x%08x"),
  2590. pAction - paf->rgoAction, pAction->dwObjID );
  2591. }
  2592. else
  2593. {
  2594. if(!( pAction->dwFlags & DIA_FORCEFEEDBACK )
  2595. || ( dfDev->rgodf[idxObj].dwType & ( DIDFT_FFACTUATOR | DIDFT_FFEFFECTTRIGGER ) ) )
  2596. {
  2597. /*
  2598. * If the game needs FF, only map FF objects
  2599. */
  2600. dwObject = dfDev->rgodf[idxObj].dwType;
  2601. }
  2602. }
  2603. break;
  2604. }
  2605. if( dwObject == (DWORD)-1 )
  2606. {
  2607. if( ( iMap == eMapClassSemantic )
  2608. && SUCCEEDED( CMap_TestSysOffset( dwPhysicalGenre,
  2609. DISEM_INDEX_GET( pAction->dwSemantic ) ) ) )
  2610. {
  2611. /*
  2612. * Don't worry that this device is less capable than some
  2613. */
  2614. continue;
  2615. }
  2616. }
  2617. }
  2618. /*
  2619. * If we get this far, we either have a possible match or the
  2620. * action is invalid. Since we could still find errors, look
  2621. * at matches first.
  2622. */
  2623. if( dwObject != -1 )
  2624. {
  2625. if( idxObj < dfDev->dwNumObjs )
  2626. {
  2627. if( iMap == eMapPrevious )
  2628. {
  2629. /*
  2630. * Validation should have caught duplicates
  2631. */
  2632. AssertF( !pMatch[idxObj] );
  2633. pMatch[idxObj] = TRUE;
  2634. continue;
  2635. }
  2636. else
  2637. {
  2638. if( pMatch[idxObj] )
  2639. {
  2640. SquirtSqflPtszV(sqflDf | sqflError,
  2641. TEXT("Object specified more than once on device"));
  2642. dwObject = (DWORD)-1;
  2643. }
  2644. }
  2645. }
  2646. else
  2647. {
  2648. hres = CMap_TestSysObject( dwPhysicalGenre, dwObject );
  2649. if( SUCCEEDED( hres ) )
  2650. {
  2651. /*
  2652. * Not an unreasonable request so just carry on
  2653. */
  2654. continue;
  2655. }
  2656. else
  2657. {
  2658. dwObject = (DWORD)-1;
  2659. }
  2660. }
  2661. }
  2662. /*
  2663. * We have either a valid object or an error
  2664. */
  2665. if( dwObject != (DWORD)-1 )
  2666. {
  2667. pAction->dwHow = DIAH_DEFAULT;
  2668. pAction->dwObjID = dwObject;
  2669. pAction->guidInstance = *guidDevInst;
  2670. SquirtSqflPtszV(sqflDf | sqflVerbose,
  2671. TEXT("Action %d mapped to object index 0x%08x type 0x%08x"),
  2672. pAction - paf->rgoAction, idxObj, dwObject );
  2673. pMatch[idxObj] = TRUE;
  2674. fSomethingMapped = TRUE;
  2675. }
  2676. else
  2677. {
  2678. /*
  2679. * Mark this action as invalid and quit.
  2680. */
  2681. pAction->dwHow = DIAH_ERROR;
  2682. RPF("ERROR BuildActionMap: arg %d: rgoAction[%d] invalid", 1, pAction - paf->rgoAction );
  2683. RPF( "Semantic 0x%08x", pAction->dwSemantic );
  2684. hres = DIERR_INVALIDPARAM;
  2685. goto free_and_exit;
  2686. }
  2687. } /* Action loop */
  2688. } /* Match loop */
  2689. /*
  2690. * The result should always be a successful memory allocation (S_OK)
  2691. */
  2692. AssertF( hres == S_OK );
  2693. /*
  2694. * If nothing was mapped, let the caller know
  2695. */
  2696. if( !fSomethingMapped )
  2697. {
  2698. hres = DI_NOEFFECT;
  2699. }
  2700. free_and_exit:;
  2701. FreePv( pMatch );
  2702. }
  2703. ExitOleProc();
  2704. return hres;
  2705. }
  2706. /*****************************************************************************
  2707. *
  2708. * @doc INTERNAL
  2709. *
  2710. * @method HRESULT | CMap | ActionMap_IsValidMapObject |
  2711. *
  2712. * Utility function to check a DIACTIONFORMAT structure for validity.
  2713. *
  2714. * @cwrap LPDIRECTINPUTDEVICE | lpDirectInputDevice
  2715. *
  2716. * @parm LPDIACTIONFORMAT | paf |
  2717. *
  2718. * Points to a structure that describes the actions needed by the
  2719. * application.
  2720. *
  2721. * @returns
  2722. *
  2723. * Returns a COM error code. The following error codes are
  2724. * intended to be illustrative and not necessarily comprehensive.
  2725. *
  2726. * <c DI_OK> = <c S_OK>: The structure is valid.
  2727. *
  2728. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: The structure is
  2729. * not valid.
  2730. *
  2731. *****************************************************************************/
  2732. HRESULT
  2733. CDIDev_ActionMap_IsValidMapObject
  2734. (
  2735. LPDIACTIONFORMATW paf
  2736. #ifdef XDEBUG
  2737. comma
  2738. LPCSTR pszProc
  2739. comma
  2740. UINT argnum
  2741. #endif
  2742. )
  2743. {
  2744. HRESULT hres = E_INVALIDARG;
  2745. /*
  2746. * Assert that the structures are the same until the final element
  2747. */
  2748. #if defined(_WIN64)
  2749. CAssertF( ( ( cbX( DIACTIONFORMATW ) - cbX( ((LPDIACTIONFORMATW)0)->tszActionMap ) )
  2750. - ( cbX( DIACTIONFORMATA ) - cbX( ((LPDIACTIONFORMATA)0)->tszActionMap ) )
  2751. < MAX_NATURAL_ALIGNMENT ) );
  2752. #else
  2753. CAssertF( ( cbX( DIACTIONFORMATW ) - cbX( ((LPDIACTIONFORMATW)0)->tszActionMap ) )
  2754. == ( cbX( DIACTIONFORMATA ) - cbX( ((LPDIACTIONFORMATA)0)->tszActionMap ) ) );
  2755. #endif
  2756. CAssertF( FIELD_OFFSET( DIACTIONFORMATW, tszActionMap )
  2757. == FIELD_OFFSET( DIACTIONFORMATA, tszActionMap ) );
  2758. CAssertF( cbX(DIACTIONA) == cbX(DIACTIONW) );
  2759. if( FAILED(hresFullValidWriteNoScramblePvCb_(paf, MAKELONG( cbX(DIACTIONFORMATA), cbX(DIACTIONFORMATW) ), pszProc, argnum)) )
  2760. {
  2761. }
  2762. else if( paf->dwActionSize != cbX(DIACTION) )
  2763. {
  2764. D( RPF("IDirectInputDevice::%s: Invalid DIACTIONFORMAT.dwActionSize 0x%08x",
  2765. pszProc, paf->dwActionSize ); )
  2766. }
  2767. else if( paf->dwDataSize != (paf->dwNumActions * cbX( ((LPDIDEVICEOBJECTDATA)0)->dwData ) ) )
  2768. {
  2769. D( RPF("IDirectInputDevice::%s: DIACTIONFORMAT.dwDataSize 0x%08x not valid for DIACTIONFORMAT.dwNumActions 0x%08x",
  2770. pszProc, paf->dwDataSize ); )
  2771. }
  2772. else if( IsEqualGUID(&paf->guidActionMap, &GUID_Null) )
  2773. {
  2774. D( RPF("IDirectInputDevice::%s: DIACTIONFORMAT.guidActionMap is a NULL GUID", pszProc ); )
  2775. }
  2776. else if( !DISEM_VIRTUAL_GET( paf->dwGenre ) )
  2777. {
  2778. D( RPF("IDirectInputDevice::%s: Invalid (1) DIACTIONFORMAT.dwGenre 0x%08x", pszProc, paf->dwGenre ); )
  2779. }
  2780. else if( DISEM_GENRE_GET( paf->dwGenre ) > DISEM_MAX_GENRE )
  2781. {
  2782. D( RPF("IDirectInputDevice::%s: Invalid (2) DIACTIONFORMAT.dwGenre 0x%08x", pszProc, paf->dwGenre ); )
  2783. }
  2784. else if( ( paf->lAxisMin | paf->lAxisMax ) && ( paf->lAxisMin > paf->lAxisMax ) )
  2785. {
  2786. D( RPF("IDirectInputDevice::%s: Invalid DIACTIONFORMAT.lAxisMin 0x%08x for lAxisMax 0x%08x",
  2787. pszProc, paf->lAxisMin, paf->lAxisMax ); )
  2788. }
  2789. else if( !paf->dwNumActions )
  2790. {
  2791. D( RPF("IDirectInputDevice::%s: DIACTIONFORMAT.dwNumActions is zero", pszProc ); )
  2792. }
  2793. else if( paf->dwNumActions & 0xFF000000 )
  2794. {
  2795. D( RPF("IDirectInputDevice::%s: DIACTIONFORMAT.dwNumActions of 0x%08x is unreasonable", paf->dwNumActions, pszProc ); )
  2796. }
  2797. else if( !paf->rgoAction )
  2798. {
  2799. D( RPF("IDirectInputDevice::%s: DIACTIONFORMAT.rgoAction is NULL", pszProc ); )
  2800. }
  2801. else if( FAILED( hresFullValidWriteNoScramblePvCb_(paf->rgoAction,
  2802. cbX(*paf->rgoAction) * paf->dwNumActions, pszProc, argnum ) ) )
  2803. {
  2804. }
  2805. else
  2806. {
  2807. hres = S_OK;
  2808. }
  2809. /*
  2810. * Warning only tests go here. Only test if everything else was OK.
  2811. */
  2812. #ifdef XDEBUG
  2813. if( SUCCEEDED( hres ) )
  2814. {
  2815. }
  2816. #endif
  2817. return hres;
  2818. }
  2819. /*****************************************************************************
  2820. *
  2821. * @doc INTERNAL
  2822. *
  2823. * @func DWORD | BitwiseReflect |
  2824. *
  2825. * Reflect the bottom bits of a value.
  2826. * Note, this could easily be optimized but it is only used once.
  2827. *
  2828. * @parm IN DWORD | dwValue |
  2829. *
  2830. * The value to be reflected.
  2831. *
  2832. * @parm IN int | iBottom |
  2833. *
  2834. * The number of bits to be reflected.
  2835. *
  2836. * @returns
  2837. * Returns the value dwValue with the bottom iBottom bits reflected
  2838. *
  2839. *****************************************************************************/
  2840. DWORD BitwiseReflect
  2841. (
  2842. DWORD dwValue,
  2843. int iBottom
  2844. )
  2845. {
  2846. int BitIdx;
  2847. DWORD dwTemp = dwValue;
  2848. #define BITMASK(X) (1L << (X))
  2849. for( BitIdx = 0; BitIdx < iBottom; BitIdx++ )
  2850. {
  2851. if( dwTemp & 1L )
  2852. dwValue |= BITMASK( ( iBottom - 1 ) - BitIdx );
  2853. else
  2854. dwValue &= ~BITMASK( ( iBottom - 1 ) - BitIdx );
  2855. dwTemp >>= 1;
  2856. }
  2857. return dwValue;
  2858. #undef BITMASK
  2859. }
  2860. /*****************************************************************************
  2861. *
  2862. * @doc INTERNAL
  2863. *
  2864. * @func HRESULT | CMap_InitializeCRCTable |
  2865. *
  2866. * If needed create and initialize the global table used for CRCs.
  2867. *
  2868. * Allocate memory for the 256 DWORD array and generate a set of
  2869. * values used to calculate a Cyclic Redundancy Check.
  2870. * The algorithm used is supposedly the same as Ethernet's CRC-32.
  2871. *
  2872. * @returns
  2873. * Returns one of the following a COM error codes:
  2874. *
  2875. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  2876. * <c DI_NOEFFECT> = <c S_FALSE>: The table already existed.
  2877. *
  2878. * <c E_OUTOFMEMORY>: insufficient memory available for the table.
  2879. * The GetMapCRC function does not check that the table has been
  2880. * initialized so failure of this function should not allow
  2881. * processing to proceed into any function that uses GetMapCRC.
  2882. *
  2883. *****************************************************************************/
  2884. #define CRC_TABLE_SIZE 256
  2885. #define CRCWIDTH 32
  2886. #define POLY 0x04C11DB7
  2887. HRESULT CMap_InitializeCRCTable( void )
  2888. {
  2889. HRESULT hres;
  2890. int TableIdx;
  2891. if( g_rgdwCRCTable )
  2892. {
  2893. hres = S_FALSE;
  2894. }
  2895. else
  2896. {
  2897. hres = AllocCbPpv( CRC_TABLE_SIZE * cbX( *g_rgdwCRCTable ), &g_rgdwCRCTable );
  2898. if( SUCCEEDED( hres ) )
  2899. {
  2900. /*
  2901. * Special case the first element so it gets a non-zero value
  2902. */
  2903. g_rgdwCRCTable[0] = POLY;
  2904. for( TableIdx = 1; TableIdx < CRC_TABLE_SIZE; TableIdx++ )
  2905. {
  2906. int BitIdx;
  2907. DWORD dwR;
  2908. dwR = BitwiseReflect( TableIdx, 8 ) << ( CRCWIDTH - 8 );
  2909. for( BitIdx = 0; BitIdx < 8; BitIdx++ )
  2910. {
  2911. if( dwR & 0x80000000 )
  2912. dwR = ( dwR << 1 ) ^ POLY;
  2913. else
  2914. dwR <<= 1;
  2915. }
  2916. g_rgdwCRCTable[TableIdx] = BitwiseReflect( dwR, CRCWIDTH );
  2917. /*
  2918. * We do not want a value of zero or identical values to be
  2919. * generated.
  2920. */
  2921. AssertF( g_rgdwCRCTable[TableIdx] );
  2922. AssertF( g_rgdwCRCTable[TableIdx] != g_rgdwCRCTable[TableIdx-1] );
  2923. }
  2924. }
  2925. }
  2926. return hres;
  2927. }
  2928. #undef CRCWIDTH
  2929. /*****************************************************************************
  2930. *
  2931. * @doc INTERNAL
  2932. *
  2933. * @func DWORD | GetMapCRC |
  2934. *
  2935. * Calculate a CRC based on the passed DIACTIONFORMAT contents.
  2936. * The algorithm used is based on "CRC-32" which is supposedly what
  2937. * Ethernet uses, however some changes have been made to suit the
  2938. * specific use.
  2939. *
  2940. * @parm IN LPDIACTIONFORMAT | lpaf |
  2941. *
  2942. * Points to a structure that describes the actions to be mapped
  2943. * for which a CRC is to be generated.
  2944. *
  2945. * @returns
  2946. *
  2947. * The 32 bit CRC as a DWORD value.
  2948. *
  2949. *****************************************************************************/
  2950. DWORD GetMapCRC
  2951. (
  2952. LPDIACTIONFORMATW paf,
  2953. REFGUID guidInst
  2954. )
  2955. {
  2956. DWORD dwCRC;
  2957. PBYTE pBuffer;
  2958. LPCDIACTIONW pAction;
  2959. /*
  2960. * It is the caller's responsibility to make sure g_rgdwCRCTable has
  2961. * been allocated and initialized.
  2962. */
  2963. AssertF( g_rgdwCRCTable );
  2964. /*
  2965. * Initialize to dwNumActions to avoid having to CRC it
  2966. */
  2967. dwCRC = paf->dwNumActions;
  2968. /* Assert that the action map guid and the genre can be tested in series */
  2969. CAssertF( FIELD_OFFSET( DIACTIONFORMATW, dwGenre )
  2970. == FIELD_OFFSET( DIACTIONFORMATW, guidActionMap ) + cbX( paf->guidActionMap ) );
  2971. for( pBuffer = ((PBYTE)&paf->guidActionMap) + cbX( paf->guidActionMap ) + cbX( paf->dwGenre );
  2972. pBuffer >= ((PBYTE)&paf->guidActionMap); pBuffer-- )
  2973. {
  2974. dwCRC = g_rgdwCRCTable[( LOBYTE(dwCRC) ^ *pBuffer )] ^ (dwCRC >> 8);
  2975. }
  2976. /* Assert that the device instance guid and object ID can be tested in series */
  2977. CAssertF( FIELD_OFFSET( DIACTIONW, dwObjID )
  2978. == FIELD_OFFSET( DIACTIONW, guidInstance ) + cbX( pAction->guidInstance ) );
  2979. for( pAction = paf->rgoAction; pAction < &paf->rgoAction[paf->dwNumActions]; pAction++ )
  2980. {
  2981. /*
  2982. * Make sure this action is really relevant before including it in
  2983. * the CRC. It is assumed that any change in which actions are
  2984. * included will be picked up in the resultant CRC.
  2985. */
  2986. if( IsEqualGUID( &pAction->guidInstance, guidInst )
  2987. && ( pAction->dwHow & DIAH_MAPMASK )
  2988. && ( ( pAction->dwFlags & DIA_APPNOMAP ) == 0 ) )
  2989. {
  2990. /*
  2991. * Besides which actions are taken into account, the only fields
  2992. * need to be verified are those that would change a SetActionMap.
  2993. * Although flags such as DIA_FORCEFEEDBACK could alter the
  2994. * mappings they do not change a SetActionMap.
  2995. */
  2996. for( pBuffer = ((PBYTE)&pAction->guidInstance) + cbX( pAction->guidInstance ) + cbX( pAction->dwObjID );
  2997. pBuffer >= ((PBYTE)&pAction->guidInstance); pBuffer-- )
  2998. {
  2999. dwCRC = g_rgdwCRCTable[( LOBYTE(dwCRC) ^ *pBuffer )] ^ (dwCRC >> 8);
  3000. }
  3001. }
  3002. }
  3003. return dwCRC;
  3004. }
  3005. /*****************************************************************************
  3006. *
  3007. * @doc INTERNAL
  3008. *
  3009. * @method HRESULT | IDirectInputDevice | CDIDev_BuildActionMapCore |
  3010. *
  3011. * Worker function for BuildActionMapA and BuildActionMapW.
  3012. * This does the real work once the external entry points have done
  3013. * dialect specific validation and set up.
  3014. *
  3015. *****************************************************************************/
  3016. STDMETHODIMP CDIDev_BuildActionMapCore
  3017. (
  3018. PDD this,
  3019. LPDIACTIONFORMATW paf,
  3020. LPCWSTR lpwszUserName,
  3021. DWORD dwFlags
  3022. )
  3023. {
  3024. HRESULT hres;
  3025. EnterProcI(CDIDev_BuildActionMapCore, (_ "pWx", paf, lpwszUserName, dwFlags ));
  3026. // This application uses the mapper
  3027. AhAppRegister(this->dwVersion, 0x1);
  3028. switch( dwFlags & ( DIDBAM_PRESERVE | DIDBAM_INITIALIZE | DIDBAM_HWDEFAULTS ) )
  3029. {
  3030. case DIDBAM_DEFAULT:
  3031. case DIDBAM_PRESERVE:
  3032. case DIDBAM_INITIALIZE:
  3033. case DIDBAM_HWDEFAULTS:
  3034. hres = S_OK;
  3035. break;
  3036. default:
  3037. RPF("ERROR %s: arg %d: Must not combine "
  3038. "DIDBAM_PRESERVE, DIDBAM_INITIALIZE and DIDBAM_HWDEFAULTS", s_szProc, 3);
  3039. hres = E_INVALIDARG;
  3040. }
  3041. if( SUCCEEDED(hres)
  3042. && SUCCEEDED(hres = hresFullValidFl(dwFlags, DIDBAM_VALID, 3))
  3043. && SUCCEEDED(hres = CMap_ValidateActionMapSemantics( paf, dwFlags ) ) )
  3044. {
  3045. LPDIPROPSTRING pdipMapFile;
  3046. if( SUCCEEDED( hres = AllocCbPpv(cbX(*pdipMapFile), &pdipMapFile) ) )
  3047. {
  3048. HRESULT hresExactMaps = E_FAIL;
  3049. PWCHAR pwszMapFile;
  3050. DWORD dwCommsType;
  3051. if( dwFlags & DIDBAM_HWDEFAULTS )
  3052. {
  3053. hres = CMap_DeviceValidateActionMap( (PV)this, paf, DVAM_DEFAULT, &dwCommsType );
  3054. hresExactMaps = hres;
  3055. if( hres == S_OK )
  3056. {
  3057. hresExactMaps = DI_NOEFFECT;
  3058. }
  3059. }
  3060. else
  3061. {
  3062. /*
  3063. * Do a generic test and map of any exact device matches
  3064. */
  3065. hres = CMap_DeviceValidateActionMap( (PV)this, paf, DVAM_GETEXACTMAPPINGS, &dwCommsType );
  3066. if( SUCCEEDED( hres ) )
  3067. {
  3068. /*
  3069. * Save the exact mapping result to combine with the result
  3070. * of semantic mapping.
  3071. */
  3072. hresExactMaps = hres;
  3073. }
  3074. }
  3075. if( SUCCEEDED( hres ) )
  3076. {
  3077. pdipMapFile->diph.dwSize = cbX(DIPROPSTRING);
  3078. pdipMapFile->diph.dwHeaderSize = cbX(DIPROPHEADER);
  3079. pdipMapFile->diph.dwObj = 0;
  3080. pdipMapFile->diph.dwHow = DIPH_DEVICE;
  3081. /*
  3082. * Try to get a configured mapping.
  3083. * If there is no IHV file there may still be a user file
  3084. */
  3085. hres = CDIDev_GetPropertyW( &this->ddW, DIPROP_MAPFILE, &pdipMapFile->diph );
  3086. pwszMapFile = SUCCEEDED( hres ) ? pdipMapFile->wsz : NULL;
  3087. if( dwCommsType )
  3088. {
  3089. /*
  3090. * Communications control device
  3091. */
  3092. if( !pwszMapFile )
  3093. {
  3094. /*
  3095. * If there's no IHV mapping there's nothing to add.
  3096. */
  3097. hres = DI_NOEFFECT;
  3098. }
  3099. else
  3100. {
  3101. /*
  3102. * Modify the genre over the call to the mapper so
  3103. * that we get physical genre mappings from the IHV
  3104. * file if no user mappings are available
  3105. */
  3106. DWORD dwAppGenre = paf->dwGenre;
  3107. paf->dwGenre = DIPHYSICAL_VOICE;
  3108. hres = this->pMS->lpVtbl->GetActionMap(this->pMS, &this->guid, pwszMapFile,
  3109. (LPDIACTIONFORMATW)paf, lpwszUserName, NULL, dwFlags );
  3110. /*
  3111. * ISSUE-2001/03/29-timgill Only want the timestamp for hardcoded devices
  3112. * ->Read again for mappings
  3113. */
  3114. if( ( dwCommsType == DI8DEVTYPEDEVICECTRL_COMMSSELECTION_HARDWIRED )
  3115. &&!( dwFlags & DIDBAM_HWDEFAULTS ) )
  3116. {
  3117. DWORD dwLowTime;
  3118. DWORD dwHighTime;
  3119. dwLowTime = paf->ftTimeStamp.dwLowDateTime;
  3120. dwHighTime = paf->ftTimeStamp.dwHighDateTime;
  3121. hres = this->pMS->lpVtbl->GetActionMap(this->pMS, &this->guid, pwszMapFile,
  3122. (LPDIACTIONFORMATW)paf, lpwszUserName, NULL, DIDBAM_HWDEFAULTS );
  3123. paf->ftTimeStamp.dwLowDateTime = dwLowTime;
  3124. paf->ftTimeStamp.dwHighDateTime = dwHighTime;
  3125. }
  3126. paf->dwGenre = dwAppGenre;
  3127. if( SUCCEEDED( hres ) )
  3128. {
  3129. if( hres == S_NOMAP )
  3130. {
  3131. /*
  3132. * Make sure we do not attempt defaults and
  3133. * the exact match return code gets back to the
  3134. * caller
  3135. */
  3136. hres = DI_NOEFFECT;
  3137. }
  3138. }
  3139. else
  3140. {
  3141. /*
  3142. * If there was an error, there are no defaults
  3143. * so quit now.
  3144. */
  3145. if( ( HRESULT_FACILITY( hres ) == FACILITY_ITF )
  3146. && ( HRESULT_CODE( hres ) > 0x0600 ) )
  3147. {
  3148. AssertF( HRESULT_CODE( hres ) < 0x0680 );
  3149. RPF( "Internal GetActionMap error 0x%08x for hardwired device", hres );
  3150. hres = DIERR_MAPFILEFAIL;
  3151. }
  3152. goto FreeAndExitCDIDev_BuildActionMapCore;
  3153. }
  3154. }
  3155. }
  3156. else if( !pwszMapFile && ( dwFlags & DIDBAM_HWDEFAULTS ) )
  3157. {
  3158. /*
  3159. * Make sure we get defaults
  3160. */
  3161. SquirtSqflPtszV(sqflDf | sqflBenign,
  3162. TEXT("Failed to GetProperty DIPROP_MAPFILE 0x%08x, default will be generated"), hres );
  3163. hres = S_NOMAP;
  3164. }
  3165. else
  3166. {
  3167. hres = this->pMS->lpVtbl->GetActionMap(this->pMS, &this->guid, pwszMapFile,
  3168. (LPDIACTIONFORMATW)paf, lpwszUserName, NULL, dwFlags);
  3169. if( ( paf->ftTimeStamp.dwHighDateTime == DIAFTS_UNUSEDDEVICEHIGH )
  3170. && ( paf->ftTimeStamp.dwLowDateTime == DIAFTS_UNUSEDDEVICELOW )
  3171. && SUCCEEDED( hres ) )
  3172. {
  3173. /*
  3174. * If the device has never been used, the saved
  3175. * mappings are either the IHV defaults or cooked up
  3176. * defaults. Unfortunately, DIMap will have marked
  3177. * them as DIAH_USERCONFIG. Some day DIMap should
  3178. * either return the true flags or return without
  3179. * changing the flags, until then, reset all the
  3180. * flags and then do a second request for defaults.
  3181. */
  3182. LPDIACTIONW pAction;
  3183. for( pAction = paf->rgoAction; pAction < &paf->rgoAction[paf->dwNumActions]; pAction++ )
  3184. {
  3185. if( ( ( pAction->dwFlags & ( DIA_APPMAPPED | DIA_APPNOMAP ) ) == 0 )
  3186. && ( pAction->dwHow & DIAH_USERCONFIG )
  3187. && IsEqualGUID( &pAction->guidInstance, &this->guid ) )
  3188. {
  3189. pAction->dwHow = DIAH_UNMAPPED;
  3190. }
  3191. }
  3192. hres = this->pMS->lpVtbl->GetActionMap(this->pMS, &this->guid, pwszMapFile,
  3193. (LPDIACTIONFORMATW)paf, lpwszUserName, NULL, DIDBAM_HWDEFAULTS);
  3194. /*
  3195. * Make sure the timestamps are still set for unused.
  3196. */
  3197. paf->ftTimeStamp.dwLowDateTime = DIAFTS_UNUSEDDEVICELOW;
  3198. paf->ftTimeStamp.dwHighDateTime = DIAFTS_UNUSEDDEVICEHIGH;
  3199. }
  3200. if( FAILED( hres ) )
  3201. {
  3202. if( ( HRESULT_FACILITY( hres ) == FACILITY_ITF )
  3203. && ( HRESULT_CODE( hres ) > 0x0600 ) )
  3204. {
  3205. AssertF( HRESULT_CODE( hres ) < 0x0680 );
  3206. RPF( "Internal GetActionMap error 0x%08x for configurable device", hres );
  3207. hres = DIERR_MAPFILEFAIL;
  3208. }
  3209. }
  3210. }
  3211. }
  3212. if( SUCCEEDED( hresExactMaps ) )
  3213. {
  3214. /*
  3215. * If we took an IHV mapping, do a default mapping on top.
  3216. * This allows IHVs to only map objects that are special
  3217. * leaving other objects to be used for whatever semantics
  3218. * match.
  3219. * Some day we should have a return code that indicates which
  3220. * type of mapping DIMap produced, until then, search the
  3221. * mappings for a HWDefault.
  3222. */
  3223. if( SUCCEEDED( hres ) && ( hres != S_NOMAP )
  3224. && ( dwCommsType != DI8DEVTYPEDEVICECTRL_COMMSSELECTION_HARDWIRED ) )
  3225. {
  3226. LPDIACTIONW pAction;
  3227. for( pAction = paf->rgoAction; pAction < &paf->rgoAction[paf->dwNumActions]; pAction++ )
  3228. {
  3229. if( ( ( pAction->dwFlags & ( DIA_APPMAPPED | DIA_APPNOMAP ) ) == 0 )
  3230. && ( pAction->dwHow & DIAH_HWDEFAULT )
  3231. && IsEqualGUID( &pAction->guidInstance, &this->guid ) )
  3232. {
  3233. hres = S_NOMAP;
  3234. break;
  3235. }
  3236. }
  3237. }
  3238. if( FAILED( hres ) || ( hres == S_NOMAP ) )
  3239. {
  3240. hres = this->pdcb->lpVtbl->BuildDefaultActionMap( this->pdcb, paf, dwFlags, &this->guid );
  3241. if( SUCCEEDED( hres ) )
  3242. {
  3243. paf->ftTimeStamp.dwLowDateTime = DIAFTS_NEWDEVICELOW;
  3244. paf->ftTimeStamp.dwHighDateTime = DIAFTS_NEWDEVICEHIGH;
  3245. SquirtSqflPtszV(sqflDf | sqflVerbose, TEXT("Default action map used"));
  3246. }
  3247. else
  3248. {
  3249. SquirtSqflPtszV(sqflDf | sqflError, TEXT("Default action map failed"));
  3250. }
  3251. }
  3252. else
  3253. {
  3254. hres = CMap_DeviceValidateActionMap( (PV)this, paf, DVAM_DEFAULT, &dwCommsType );
  3255. if( SUCCEEDED( hres ) )
  3256. {
  3257. SquirtSqflPtszV(sqflDf | sqflVerbose, TEXT("Action map validated"));
  3258. }
  3259. else
  3260. {
  3261. RPF( "Initially valid action map invalidated by mapper!" );
  3262. }
  3263. }
  3264. /*
  3265. * If no semantics mapped, return the exact map result.
  3266. */
  3267. if( hres == DI_NOEFFECT )
  3268. {
  3269. hres = hresExactMaps;
  3270. }
  3271. if( dwFlags & DIDBAM_HWDEFAULTS )
  3272. {
  3273. /*
  3274. * Timestamps are meaningless for hardware defaults
  3275. * so just make sure the values are consistent.
  3276. */
  3277. paf->ftTimeStamp.dwLowDateTime = DIAFTS_UNUSEDDEVICELOW;
  3278. paf->ftTimeStamp.dwHighDateTime = DIAFTS_UNUSEDDEVICEHIGH;
  3279. }
  3280. else if( ( paf->ftTimeStamp.dwHighDateTime == DIAFTS_NEWDEVICEHIGH )
  3281. && ( paf->ftTimeStamp.dwLowDateTime == DIAFTS_NEWDEVICELOW )
  3282. && SUCCEEDED( hres ) )
  3283. {
  3284. if( FAILED( this->pMS->lpVtbl->SaveActionMap( this->pMS, &this->guid,
  3285. pwszMapFile, paf, lpwszUserName, dwFlags ) ) )
  3286. {
  3287. SquirtSqflPtszV(sqflDf | sqflBenign,
  3288. TEXT("Failed to save action map on first use 0x%08x"), hres );
  3289. paf->ftTimeStamp.dwLowDateTime = DIAFTS_UNUSEDDEVICELOW;
  3290. paf->ftTimeStamp.dwHighDateTime = DIAFTS_UNUSEDDEVICEHIGH;
  3291. /*
  3292. * Don't return an internal DIMap result, convert it to a published one
  3293. */
  3294. if( ( HRESULT_FACILITY( hres ) == FACILITY_ITF )
  3295. && ( HRESULT_CODE( hres ) > 0x0600 ) )
  3296. {
  3297. AssertF( HRESULT_CODE( hres ) < 0x0680 );
  3298. hres = DIERR_MAPFILEFAIL;
  3299. }
  3300. }
  3301. }
  3302. }
  3303. else
  3304. {
  3305. SquirtSqflPtszV(sqflDf | sqflError, TEXT("Invalid mappings in action array"));
  3306. }
  3307. FreeAndExitCDIDev_BuildActionMapCore:;
  3308. FreePv( pdipMapFile );
  3309. if( SUCCEEDED( hres ) )
  3310. {
  3311. paf->dwCRC = GetMapCRC( paf, &this->guid );
  3312. }
  3313. }
  3314. else
  3315. {
  3316. /*
  3317. * Note, we could try to do a default map even though we could not
  3318. * allocate space for the file name property but if allocations
  3319. * are failing we're better of quitting ASAP.
  3320. */
  3321. SquirtSqflPtszV(sqflDf | sqflError, TEXT("Mem allocation failure") );
  3322. }
  3323. }
  3324. #if 0
  3325. {
  3326. LPDIACTIONW pAction;
  3327. RPF( "Action map leaving build" );
  3328. // RPF( "Act# Semantic Flags Object How App Data" );
  3329. RPF( "A# Semantic Device Object How" );
  3330. for( pAction = paf->rgoAction; pAction < &paf->rgoAction[paf->dwNumActions]; pAction++ )
  3331. {
  3332. RPF( "%02d %08x {%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X} %08x %08x",
  3333. pAction - paf->rgoAction,
  3334. pAction->dwSemantic,
  3335. pAction->guidInstance.Data1, pAction->guidInstance.Data2, pAction->guidInstance.Data3,
  3336. pAction->guidInstance.Data4[0], pAction->guidInstance.Data4[1],
  3337. pAction->guidInstance.Data4[2], pAction->guidInstance.Data4[3],
  3338. pAction->guidInstance.Data4[4], pAction->guidInstance.Data4[5],
  3339. pAction->guidInstance.Data4[6], pAction->guidInstance.Data4[7],
  3340. pAction->dwObjID,
  3341. pAction->dwHow,
  3342. pAction->uAppData );
  3343. // RPF( "%02d %08x %08x %08x %08x %08x",
  3344. // pAction - paf->rgoAction,
  3345. // pAction->dwSemantic,
  3346. // pAction->dwFlags,
  3347. // pAction->dwObjID,
  3348. // pAction->dwHow,
  3349. // pAction->uAppData );
  3350. }
  3351. RPF( "--" );
  3352. }
  3353. #endif
  3354. ExitOleProc();
  3355. return hres;
  3356. }
  3357. /*****************************************************************************
  3358. *
  3359. * @doc EXTERNAL
  3360. *
  3361. * @method HRESULT | IDirectInputDevice | BuildActionMap |
  3362. *
  3363. * Obtains the mapping of actions described in the <t DIACTIONFORMAT>
  3364. * to controls for this device.
  3365. * Information about user preferences and hardware manufacturer
  3366. * provided defaults is used to create the association between game
  3367. * actions and device controls.
  3368. *
  3369. * @cwrap LPDIRECTINPUTDEVICE | lpDirectInputDevice
  3370. *
  3371. * @parm LPDIACTIONFORMAT | paf |
  3372. *
  3373. * Points to a structure that describes the actions needed by the
  3374. * application.
  3375. *
  3376. * @parm LPCSTR | lpszUserName |
  3377. *
  3378. * Name of user for whom mapping is requested. This may be a NULL
  3379. * pointer in which case the current user is assumed.
  3380. *
  3381. * @parm DWORD | dwFlags |
  3382. *
  3383. * Flags used to control the mapping. Must be a valid combination
  3384. * of the <c DIDBAM_*> flags.
  3385. *
  3386. * @returns
  3387. *
  3388. * Returns a COM error code. The following error codes are
  3389. * intended to be illustrative and not necessarily comprehensive.
  3390. *
  3391. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  3392. *
  3393. * <c DI_NOEFFECT> = <c S_OK>: The operation completed successfully
  3394. * but no actions were mapped.
  3395. *
  3396. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: A parameter is invalid.
  3397. *
  3398. *****************************************************************************/
  3399. STDMETHODIMP CDIDev_BuildActionMapW
  3400. (
  3401. PV pdidW,
  3402. LPDIACTIONFORMATW paf,
  3403. LPCWSTR lpwszUserName,
  3404. DWORD dwFlags
  3405. )
  3406. {
  3407. HRESULT hres;
  3408. EnterProcR(IDirectInputDevice8W::BuildActionMap, (_ "ppWx", pdidW, paf, lpwszUserName, dwFlags));
  3409. if( SUCCEEDED(hres = hresPvW( pdidW ) )
  3410. && SUCCEEDED(hres = CDIDev_ActionMap_IsValidMapObject( paf D(comma s_szProc comma 1) ) ) )
  3411. {
  3412. if( paf->dwSize != cbX(DIACTIONFORMATW) )
  3413. {
  3414. D( RPF("IDirectInputDevice::%s: Invalid DIACTIONFORMATW.dwSize 0x%08x",
  3415. s_szProc, paf->dwSize ); )
  3416. hres = E_INVALIDARG;
  3417. }
  3418. else
  3419. {
  3420. LPWSTR pwszGoodUserName;
  3421. hres = GetWideUserName( NULL, lpwszUserName, &pwszGoodUserName );
  3422. if( SUCCEEDED( hres ) )
  3423. {
  3424. hres = CDIDev_BuildActionMapCore( _thisPvNm(pdidW, ddW), paf, lpwszUserName, dwFlags );
  3425. if( !lpwszUserName )
  3426. {
  3427. FreePv( pwszGoodUserName );
  3428. }
  3429. }
  3430. }
  3431. }
  3432. ExitOleProc();
  3433. return hres;
  3434. }
  3435. /*****************************************************************************
  3436. *
  3437. * @doc INTERNAL
  3438. *
  3439. * @method HRESULT | IDirectInputDevice | BuildActionMapA |
  3440. *
  3441. * ANSI version of BuildActionMap.
  3442. *
  3443. *****************************************************************************/
  3444. STDMETHODIMP CDIDev_BuildActionMapA
  3445. (
  3446. PV pdidA,
  3447. LPDIACTIONFORMATA pafA,
  3448. LPCSTR lpszUserName,
  3449. DWORD dwFlags
  3450. )
  3451. {
  3452. HRESULT hres;
  3453. EnterProcR(IDirectInputDevice8A::BuildActionMap, (_ "ppAx", pdidA, pafA, lpszUserName, dwFlags));
  3454. if( SUCCEEDED(hres = hresPvA( pdidA ) )
  3455. && SUCCEEDED(hres = CDIDev_ActionMap_IsValidMapObject( (LPDIACTIONFORMATW)pafA D(comma s_szProc comma 1) ) ) )
  3456. {
  3457. if( pafA->dwSize != cbX(DIACTIONFORMATA) )
  3458. {
  3459. D( RPF("IDirectInputDevice::%s: Invalid DIACTIONFORMATA.dwSize 0x%08x",
  3460. s_szProc, pafA->dwSize ); )
  3461. hres = E_INVALIDARG;
  3462. }
  3463. else
  3464. {
  3465. LPWSTR pwszGoodUserName;
  3466. hres = GetWideUserName( lpszUserName, NULL, &pwszGoodUserName );
  3467. if( SUCCEEDED( hres ) )
  3468. {
  3469. /*
  3470. * For the sake of the mapper DLLs validation set the size to
  3471. * the UNICODE version. If we ever send this to an external
  3472. * component we should do this differently.
  3473. */
  3474. pafA->dwSize = cbX(DIACTIONFORMATW);
  3475. hres = CDIDev_BuildActionMapCore( _thisPvNm(pdidA, ddA), (LPDIACTIONFORMATW)pafA, pwszGoodUserName, dwFlags );
  3476. pafA->dwSize = cbX(DIACTIONFORMATA);
  3477. FreePv( pwszGoodUserName );
  3478. }
  3479. }
  3480. }
  3481. ExitOleProc();
  3482. return hres;
  3483. }
  3484. /*****************************************************************************
  3485. *
  3486. * @doc INTERNAL
  3487. *
  3488. * @method HRESULT | IDirectInputDevice | CDIDev_SaveActionMap |
  3489. *
  3490. * Worker function for SetActionMapA and SetActionMapW.
  3491. * Used to save an actions map.
  3492. *
  3493. *****************************************************************************/
  3494. STDMETHODIMP CDIDev_SaveActionMap
  3495. (
  3496. PDD this,
  3497. LPDIACTIONFORMATW paf,
  3498. LPWSTR lpwszUserName,
  3499. DWORD dwFlags
  3500. )
  3501. {
  3502. HRESULT hres;
  3503. LPDIPROPSTRING pdipMapFile;
  3504. EnterProcI(CDIDev_SaveActionMap, (_ "pWAx", paf, lpwszUserName, dwFlags));
  3505. if( SUCCEEDED( hres = AllocCbPpv(cbX(*pdipMapFile), &pdipMapFile) ) )
  3506. {
  3507. DWORD dwLowTime;
  3508. DWORD dwHighTime;
  3509. // Save user's pass-in timestamps
  3510. dwLowTime = paf->ftTimeStamp.dwLowDateTime;
  3511. dwHighTime = paf->ftTimeStamp.dwHighDateTime;
  3512. pdipMapFile->diph.dwSize = cbX(DIPROPSTRING);
  3513. pdipMapFile->diph.dwHeaderSize = cbX(DIPROPHEADER);
  3514. pdipMapFile->diph.dwObj = 0;
  3515. pdipMapFile->diph.dwHow = DIPH_DEVICE;
  3516. paf->ftTimeStamp.dwLowDateTime = DIAFTS_UNUSEDDEVICELOW;
  3517. paf->ftTimeStamp.dwHighDateTime = DIAFTS_UNUSEDDEVICEHIGH;
  3518. hres = CDIDev_GetPropertyW( &this->ddW, DIPROP_MAPFILE, &pdipMapFile->diph );
  3519. hres = this->pMS->lpVtbl->SaveActionMap( this->pMS, &this->guid,
  3520. /* No map file if the GetProperty failed */
  3521. (SUCCEEDED( hres )) ? pdipMapFile->wsz : NULL,
  3522. paf, lpwszUserName, dwFlags );
  3523. // restore user's pass-in timestamps
  3524. paf->ftTimeStamp.dwLowDateTime = dwLowTime;
  3525. paf->ftTimeStamp.dwHighDateTime = dwHighTime;
  3526. FreePv( pdipMapFile );
  3527. }
  3528. ExitOleProc();
  3529. return hres;
  3530. }
  3531. /*****************************************************************************
  3532. *
  3533. * @doc INTERNAL
  3534. *
  3535. * @method HRESULT | CDIDev | ParseActionFormat |
  3536. *
  3537. * Parse the action format passed by the application and
  3538. * convert it into a format that we can use to translate
  3539. * the device data into application data.
  3540. *
  3541. * @parm IN LPDIACTIONFORMAT | lpaf |
  3542. *
  3543. * Points to a structure that describes the actions to be mapped
  3544. * to this device.
  3545. *
  3546. * @returns
  3547. *
  3548. * Returns a COM error code. The following error codes are
  3549. * intended to be illustrative and not necessarily comprehensive.
  3550. *
  3551. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  3552. *
  3553. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: The
  3554. * <p lpvData> parameter is not a valid pointer.
  3555. *
  3556. *
  3557. *****************************************************************************/
  3558. STDMETHODIMP
  3559. CDIDev_ParseActionFormat
  3560. (
  3561. PDD this,
  3562. LPDIACTIONFORMATW paf
  3563. )
  3564. {
  3565. PDIXLAT pdix;
  3566. PINT rgiobj;
  3567. VXDDATAFORMAT vdf;
  3568. HRESULT hres;
  3569. #ifdef DEBUG
  3570. EnterProc(CDIDev_ParseActionFormat, (_ "pp", this, paf));
  3571. #endif
  3572. /*
  3573. * Caller should've nuked the old translation table.
  3574. */
  3575. AssertF(this->pdix == 0);
  3576. AssertF(this->rgiobj == 0);
  3577. if( paf->dwDataSize != paf->dwNumActions * cbX( ((LPDIDEVICEOBJECTDATA)0)->dwData ) )
  3578. {
  3579. SquirtSqflPtszV(sqflDf | sqflError,
  3580. TEXT("Incorrect dwDataSize (0x%08X) for dwNumActions (0x%08X)"),
  3581. paf->dwDataSize, paf->dwNumActions );
  3582. hres = E_INVALIDARG;
  3583. goto done_without_free;
  3584. }
  3585. vdf.cbData = this->df.dwDataSize;
  3586. vdf.pDfOfs = 0;
  3587. rgiobj = 0;
  3588. if( SUCCEEDED(hres = AllocCbPpv(cbCxX(this->df.dwNumObjs, DIXLAT), &pdix))
  3589. && SUCCEEDED(hres = AllocCbPpv(cbCdw(this->df.dwDataSize), &vdf.pDfOfs))
  3590. && SUCCEEDED(hres = AllocCbPpv(cbCdw(paf->dwDataSize), &rgiobj)) )
  3591. {
  3592. LPCDIACTIONW pAction;
  3593. DIPROPDWORD dipdw;
  3594. DIPROPRANGE diprange;
  3595. DWORD dwAxisMode = DIPROPAXISMODE_REL;
  3596. BOOL fSomethingMapped = FALSE;
  3597. BOOL fAxisModeKnown = FALSE;
  3598. /*
  3599. * Pre-init all the translation tags to -1,
  3600. * which means "not in use"
  3601. */
  3602. memset(pdix, 0xFF, cbCxX(this->df.dwNumObjs, DIXLAT));
  3603. memset(vdf.pDfOfs, 0xFF, cbCdw(this->df.dwDataSize));
  3604. memset(rgiobj, 0xFF, cbCdw(paf->dwDataSize) );
  3605. /*
  3606. * Set up the property invariants
  3607. */
  3608. dipdw.diph.dwSize = sizeof(DIPROPDWORD);
  3609. dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
  3610. dipdw.diph.dwHow = DIPH_BYID;
  3611. diprange.diph.dwSize = sizeof(DIPROPRANGE);
  3612. diprange.diph.dwHeaderSize = sizeof(DIPROPHEADER);
  3613. diprange.diph.dwHow = DIPH_BYID;
  3614. diprange.lMin = paf->lAxisMin;
  3615. diprange.lMax = paf->lAxisMax;
  3616. for( pAction = paf->rgoAction; pAction < &paf->rgoAction[paf->dwNumActions]; pAction++ )
  3617. {
  3618. if( IsEqualGUID( &pAction->guidInstance, &this->guid ) )
  3619. {
  3620. /*
  3621. * These flags have already been validated but it does not hurt to assert
  3622. */
  3623. AssertF( ( pAction->dwHow & ~DIAH_VALID ) == 0 );
  3624. AssertF( ( pAction->dwHow & DIAH_ERROR ) == 0 );
  3625. AssertF( ( pAction->dwFlags & ~DIA_VALID ) == 0 );
  3626. if( ( pAction->dwHow & DIAH_MAPMASK )
  3627. && ( ( pAction->dwFlags & DIA_APPNOMAP ) == 0 ) )
  3628. {
  3629. int iobjDev = -1;
  3630. PCODF podfFound;
  3631. for( podfFound = this->df.rgodf; podfFound < &this->df.rgodf[this->df.dwNumObjs]; podfFound++ )
  3632. {
  3633. iobjDev++;
  3634. /*
  3635. * Look for an exact type flags match
  3636. */
  3637. if( podfFound->dwType == pAction->dwObjID )
  3638. {
  3639. break;
  3640. }
  3641. }
  3642. if( podfFound < &this->df.rgodf[this->df.dwNumObjs] )
  3643. {
  3644. DWORD dwAppOffset = (DWORD)(pAction - paf->rgoAction) * cbX( ((LPDIDEVICEOBJECTDATA)0)->dwData );
  3645. fSomethingMapped = TRUE;
  3646. vdf.pDfOfs[podfFound->dwOfs] = iobjDev;
  3647. rgiobj[dwAppOffset] = iobjDev;
  3648. pdix[iobjDev].dwOfs = dwAppOffset;
  3649. pdix[iobjDev].uAppData = pAction->uAppData;
  3650. if ( podfFound->dwFlags & DIDOI_POLLED ) {
  3651. this->fPolledDataFormat = TRUE;
  3652. }
  3653. dipdw.diph.dwObj = podfFound->dwType;
  3654. dipdw.dwData = 0x1; // Enable this report ID
  3655. hres = CDIDev_RealSetProperty(this, DIPROP_ENABLEREPORTID, &dipdw.diph);
  3656. if ( hres == E_NOTIMPL )
  3657. {
  3658. hres = S_OK;
  3659. }
  3660. else if( FAILED( hres ) )
  3661. {
  3662. SquirtSqflPtszV(sqflDf | sqflError,
  3663. TEXT("Could not set DIPROP_ENABLEREPORTID for object 0x%08x, error 0x%08x"),
  3664. pAction->dwObjID, hres);
  3665. /*
  3666. * Ouch! Can't carry on or the error will be lost so quit
  3667. */
  3668. break;
  3669. }
  3670. /*
  3671. * Set the default axis parameters
  3672. */
  3673. if( DISEM_TYPE_GET( pAction->dwSemantic ) == DISEM_TYPE_GET( DISEM_TYPE_AXIS ) )
  3674. {
  3675. if( podfFound->dwType & DIDFT_ABSAXIS )
  3676. {
  3677. if( !fAxisModeKnown )
  3678. {
  3679. fAxisModeKnown = TRUE;
  3680. dwAxisMode = DIPROPAXISMODE_ABS;
  3681. }
  3682. if( !( pAction->dwFlags & DIA_NORANGE )
  3683. && ( diprange.lMin | diprange.lMax ) )
  3684. {
  3685. diprange.diph.dwObj = podfFound->dwType;
  3686. hres = CDIDev_RealSetProperty(this, DIPROP_RANGE, &diprange.diph);
  3687. if( FAILED( hres ) )
  3688. {
  3689. SquirtSqflPtszV(sqflDf | sqflBenign,
  3690. TEXT("failed (0x%08x) to set range on mapped axis action"),
  3691. hres );
  3692. }
  3693. /*
  3694. * Ranges cannot be set on natively relative
  3695. * axes so don't worry what the result is.
  3696. */
  3697. hres = S_OK;
  3698. }
  3699. }
  3700. else
  3701. {
  3702. /*
  3703. * dwAxisMode is initialized to DIPROPAXISMODE_REL
  3704. * so that this code path is the same as the one
  3705. * for DIDF_ABSAXIS as far as it goes. Compilers
  3706. * are good at delaying branches to remove such
  3707. * duplication.
  3708. */
  3709. if( !fAxisModeKnown )
  3710. {
  3711. fAxisModeKnown = TRUE;
  3712. }
  3713. }
  3714. }
  3715. }
  3716. else
  3717. {
  3718. SquirtSqflPtszV(sqflDf | sqflError,
  3719. TEXT("mapped action format contains invalid object 0x%08x"),
  3720. pAction->dwObjID );
  3721. hres = E_INVALIDARG;
  3722. goto done;
  3723. }
  3724. }
  3725. }
  3726. #ifdef XDEBUG
  3727. else
  3728. {
  3729. if( ( pAction->dwHow & ~DIAH_VALID )
  3730. || ( pAction->dwHow & DIAH_ERROR )
  3731. || ( pAction->dwFlags & ~DIA_VALID ) )
  3732. {
  3733. SquirtSqflPtszV(sqflDf | sqflBenign,
  3734. TEXT("action format contains invalid object 0x%08x"),
  3735. pAction->dwObjID );
  3736. RPF("rgoAction[%d].dwHow 0x%08x or rgoAction[%d].dwFlags 0x%08x is invalid",
  3737. pAction - paf->rgoAction, pAction->dwHow,
  3738. pAction - paf->rgoAction, pAction->dwFlags );
  3739. }
  3740. }
  3741. #endif
  3742. }
  3743. if( !fSomethingMapped )
  3744. {
  3745. SquirtSqflPtszV(sqflDf | sqflBenign, TEXT("No actions mapped") );
  3746. hres = DI_NOEFFECT;
  3747. goto done;
  3748. }
  3749. #ifdef DEBUG
  3750. /*
  3751. * Double-check the lookup tables just to preserve our sanity.
  3752. */
  3753. {
  3754. UINT dwOfs;
  3755. for ( dwOfs = 0; dwOfs < paf->dwNumActions; dwOfs++ )
  3756. {
  3757. if ( rgiobj[dwOfs] >= 0 ) {
  3758. AssertF(pdix[rgiobj[dwOfs]].dwOfs == dwOfs);
  3759. } else {
  3760. AssertF(rgiobj[dwOfs] == -1);
  3761. }
  3762. }
  3763. }
  3764. #endif
  3765. vdf.pvi = this->pvi;
  3766. if ( fLimpFF(this->pvi,
  3767. SUCCEEDED(hres = Hel_SetDataFormat(&vdf))) ) {
  3768. this->pdix = pdix;
  3769. pdix = 0;
  3770. this->rgiobj = rgiobj;
  3771. rgiobj = 0;
  3772. this->dwDataSize = paf->dwDataSize;
  3773. /*
  3774. * Now that the lower level knows what it's dealing with set
  3775. * the default buffer size.
  3776. */
  3777. dipdw.diph.dwObj = 0;
  3778. dipdw.diph.dwHow = DIPH_DEVICE;
  3779. dipdw.dwData = paf->dwBufferSize;
  3780. hres = CDIDev_RealSetProperty(this, DIPROP_BUFFERSIZE, &dipdw.diph);
  3781. if( SUCCEEDED( hres ) )
  3782. {
  3783. if( fAxisModeKnown )
  3784. {
  3785. AssertF( ( dwAxisMode == DIPROPAXISMODE_REL ) || ( dwAxisMode == DIPROPAXISMODE_ABS ) );
  3786. dipdw.dwData = dwAxisMode;
  3787. D( hres = )
  3788. CDIDev_RealSetProperty(this, DIPROP_AXISMODE, &dipdw.diph);
  3789. AssertF( SUCCEEDED( hres ) );
  3790. }
  3791. /*
  3792. * Complete success, whatever (success) SetProperty returns
  3793. * assume that DIPROP_AXISMODE will never fail from here.
  3794. */
  3795. hres = S_OK;
  3796. }
  3797. else
  3798. {
  3799. SquirtSqflPtszV(sqflDf | sqflError,
  3800. TEXT("failed (0x%08x) to set buffer size 0x%0x8 for device"),
  3801. hres );
  3802. hres = E_INVALIDARG;
  3803. }
  3804. } else {
  3805. AssertF(FAILED(hres));
  3806. }
  3807. } else {
  3808. /* Out of memory */
  3809. }
  3810. done:;
  3811. FreePpv(&pdix);
  3812. FreePpv(&rgiobj);
  3813. FreePpv(&vdf.pDfOfs);
  3814. done_without_free:;
  3815. #ifdef DEBUG
  3816. ExitOleProc();
  3817. #endif
  3818. return hres;
  3819. }
  3820. /*****************************************************************************
  3821. *
  3822. * @doc INTERNAL
  3823. *
  3824. * @method HRESULT | IDirectInputDevice | CDIDev_SetDataFormatFromMap |
  3825. *
  3826. * Worker function for SetActionMapA and SetActionMapW.
  3827. * Used to set a data format based on passed mapped actions.
  3828. *
  3829. *****************************************************************************/
  3830. STDMETHODIMP
  3831. CDIDev_SetDataFormatFromMap
  3832. (
  3833. PDD this,
  3834. LPDIACTIONFORMATW paf
  3835. )
  3836. {
  3837. HRESULT hres;
  3838. EnterProcI(CDIDev_SetDataFormatFromMap, (_ "p", paf));
  3839. if( !paf->dwBufferSize )
  3840. {
  3841. SquirtSqflPtszV(sqflDf | sqflVerbose,
  3842. TEXT("%S: zero DIACTIONFORMAT.dwBufferSize, may need to set yourself"),
  3843. s_szProc );
  3844. }
  3845. if( paf->dwBufferSize > DEVICE_MAXBUFFERSIZE )
  3846. {
  3847. RPF("IDirectInputDevice::%s: DIACTIONFORMAT.dwBufferSize of 0x%08x is very large",
  3848. s_szProc, paf->dwBufferSize );
  3849. }
  3850. /*
  3851. * Must protect with the critical section to prevent two people
  3852. * from changing the format simultaneously, or one person from
  3853. * changing the data format while somebody else is reading data.
  3854. */
  3855. CDIDev_EnterCrit(this);
  3856. if( !this->fAcquired )
  3857. {
  3858. DIPROPDWORD dipdw;
  3859. /*
  3860. * Nuke the old data format stuff before proceeding.
  3861. * Include the "failed POV" array as we can't fail and continue.
  3862. */
  3863. FreePpv(&this->pdix);
  3864. FreePpv(&this->rgiobj);
  3865. FreePpv(&this->rgdwPOV);
  3866. this->cdwPOV = 0;
  3867. D(this->GetState = 0);
  3868. this->fPolledDataFormat = FALSE;
  3869. /*
  3870. * Wipe out the report IDs
  3871. */
  3872. dipdw.diph.dwSize = sizeof(DIPROPDWORD);
  3873. dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
  3874. dipdw.diph.dwObj = 0x0;
  3875. dipdw.diph.dwHow = DIPH_DEVICE;
  3876. dipdw.dwData = 0; // Nuke all knowledge of reportId's
  3877. hres = CDIDev_RealSetProperty(this, DIPROP_ENABLEREPORTID, &dipdw.diph);
  3878. if( SUCCEEDED(hres) || hres == E_NOTIMPL )
  3879. {
  3880. hres = CDIDev_ParseActionFormat(this, paf);
  3881. /*
  3882. * If other success codes are implemented, this check should
  3883. * be modified to ( SUCCEEDED( hres ) && ( hres != DI_NOEFFECT ) )
  3884. */
  3885. AssertF( ( hres == S_OK ) || ( hres == DI_NOEFFECT ) || FAILED( hres ) );
  3886. if( hres == S_OK )
  3887. {
  3888. hres = CDIDev_OptimizeDataFormat(this);
  3889. }
  3890. }
  3891. else
  3892. {
  3893. SquirtSqflPtszV(sqflDf | sqflVerbose,
  3894. TEXT("Could not set DIPROP_ENABLEREPORTID to 0x0"));
  3895. }
  3896. }
  3897. else
  3898. { /* Already acquired */
  3899. hres = DIERR_ACQUIRED;
  3900. }
  3901. CDIDev_LeaveCrit(this);
  3902. ExitOleProcR();
  3903. return hres;
  3904. }
  3905. /*****************************************************************************
  3906. *
  3907. * @doc INTERNAL
  3908. *
  3909. * @method HRESULT | IDirectInputDevice | SetActionMapCore |
  3910. *
  3911. * Worker function, does all the real work for SetActionMapW and
  3912. * SetActionMapA. See SetActionMapW for details.
  3913. *
  3914. *****************************************************************************/
  3915. STDMETHODIMP CDIDev_SetActionMapCore
  3916. (
  3917. PDD this,
  3918. LPDIACTIONFORMATW paf,
  3919. LPWSTR lpwszUserName,
  3920. LPSTR lpszUserName,
  3921. DWORD dwFlags
  3922. )
  3923. {
  3924. HRESULT hres;
  3925. EnterProcI(IDirectInputDevice8::SetActionMapCore, (_ "pxWA", paf, dwFlags, lpwszUserName, lpszUserName ));
  3926. if( SUCCEEDED( hres = hresFullValidFl( dwFlags, DIDSAM_VALID, 3 ) ) )
  3927. {
  3928. if( dwFlags & DIDSAM_NOUSER )
  3929. {
  3930. if( dwFlags & ~DIDSAM_NOUSER )
  3931. {
  3932. RPF( "IDirectInputDevice8::SetActionMap: Invalid dwFlags 0x%08x, cannot use DIDSAM_NOUSER with other flags" );
  3933. hres = E_INVALIDARG;
  3934. }
  3935. else
  3936. {
  3937. hres = CMap_SetDeviceUserName( &this->guid, NULL );
  3938. }
  3939. }
  3940. else
  3941. {
  3942. DWORD dwCRC;
  3943. LPWSTR pwszGoodUserName;
  3944. hres = GetWideUserName( lpszUserName, lpwszUserName, &pwszGoodUserName );
  3945. if( SUCCEEDED( hres ) )
  3946. {
  3947. dwCRC = GetMapCRC( paf, &this->guid );
  3948. if( ( paf->dwCRC != dwCRC )
  3949. || CMap_IsNewDeviceUserName( &this->guid, pwszGoodUserName ) )
  3950. {
  3951. /*
  3952. * Set the force save flag so we only have to test one bit later
  3953. */
  3954. dwFlags |= DIDSAM_FORCESAVE;
  3955. }
  3956. if( dwFlags & DIDSAM_FORCESAVE )
  3957. {
  3958. hres = CMap_ValidateActionMapSemantics( paf, DIDBAM_PRESERVE );
  3959. if( SUCCEEDED( hres ) )
  3960. {
  3961. DWORD dwDummy;
  3962. hres = CMap_DeviceValidateActionMap( (PV)this, paf, DVAM_DEFAULT, &dwDummy );
  3963. if( FAILED( hres ) )
  3964. {
  3965. SquirtSqflPtszV(sqflDf | sqflError, TEXT("Action map invalid on SetActionMap"));
  3966. }
  3967. else if( ( hres == DI_WRITEPROTECT ) && ( paf->dwCRC != dwCRC ) )
  3968. {
  3969. RPF( "Refusing changed mappings for hardcoded device" );
  3970. hres = DIERR_INVALIDPARAM;
  3971. }
  3972. }
  3973. else
  3974. {
  3975. SquirtSqflPtszV(sqflDf | sqflError, TEXT("Action map invalid on SetActionMap"));
  3976. }
  3977. }
  3978. if( SUCCEEDED( hres ) )
  3979. {
  3980. if( SUCCEEDED( hres = CMap_SetDeviceUserName( &this->guid, pwszGoodUserName ) )
  3981. && SUCCEEDED( hres = CDIDev_SetDataFormatFromMap( this, paf ) ) )
  3982. {
  3983. if( dwFlags & DIDSAM_FORCESAVE )
  3984. {
  3985. hres = CDIDev_SaveActionMap( this, paf, pwszGoodUserName, dwFlags );
  3986. if( SUCCEEDED( hres ) )
  3987. {
  3988. //We don't remap success code anywhere so
  3989. //assert it is what we expected
  3990. AssertF(hres==S_OK);
  3991. paf->dwCRC = dwCRC;
  3992. }
  3993. else
  3994. {
  3995. RPF( "Ignoring internal SaveActionMap error 0x%08x", hres );
  3996. hres = DI_SETTINGSNOTSAVED;
  3997. }
  3998. }
  3999. }
  4000. }
  4001. if( !lpwszUserName )
  4002. {
  4003. /*
  4004. * Free either the default name or the ANSI translation
  4005. */
  4006. FreePv( pwszGoodUserName );
  4007. }
  4008. }
  4009. }
  4010. }
  4011. ExitOleProc();
  4012. return hres;
  4013. }
  4014. /*****************************************************************************
  4015. *
  4016. * @doc EXTERNAL
  4017. *
  4018. * @method HRESULT | IDirectInputDevice | SetActionMap |
  4019. *
  4020. * Set the data format for the DirectInput device from
  4021. * an action map for the passed application and user.
  4022. *
  4023. * If the action map has been changed (as determined by a CRC check)
  4024. * this latest map is saved after it has been applied.
  4025. *
  4026. * The data format must be set before the device can be
  4027. * acquired.
  4028. *
  4029. * It is necessary to set the data format only once.
  4030. *
  4031. * The data format may not be changed while the device
  4032. * is acquired.
  4033. *
  4034. * If the attempt to set the data format fails, all data
  4035. * format information is lost, and a valid data format
  4036. * must be set before the device may be acquired.
  4037. *
  4038. * @cwrap LPDIRECTINPUTDEVICE | lpDirectInputDevice
  4039. *
  4040. * @parm LPDIACTIONFORMAT | paf |
  4041. *
  4042. * Points to a structure that describes the actions needed by the
  4043. * application.
  4044. *
  4045. * @parm LPCTSTR | lptszUserName |
  4046. *
  4047. * Name of user for whom mapping is being set. This may be a NULL
  4048. * pointer in which case the current user is assumed.
  4049. *
  4050. * @parm DWORD | dwFlags |
  4051. *
  4052. * Flags used to control how the mapping should be set.
  4053. * Must be a valid combination of the <c DIDSAM_*> flags.
  4054. *
  4055. * @returns
  4056. *
  4057. * Returns a COM error code. The following error codes are
  4058. * intended to be illustrative and not necessarily comprehensive.
  4059. *
  4060. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  4061. *
  4062. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: A parameter is invalid.
  4063. *
  4064. * <c DIERR_ACQUIRED>: Cannot apply an action map while the device
  4065. * is acquired.
  4066. *
  4067. *****************************************************************************/
  4068. STDMETHODIMP CDIDev_SetActionMapW
  4069. (
  4070. PV pdidW,
  4071. LPDIACTIONFORMATW pafW,
  4072. LPCWSTR lpwszUserName,
  4073. DWORD dwFlags
  4074. )
  4075. {
  4076. HRESULT hres;
  4077. EnterProcR(IDirectInputDevice8W::SetActionMap, (_ "ppWx", pdidW, pafW, lpwszUserName, dwFlags));
  4078. if( ( SUCCEEDED( hres = hresPvW( pdidW ) ) )
  4079. && ( SUCCEEDED( hres = CDIDev_ActionMap_IsValidMapObject( pafW D(comma s_szProc comma 1) ) ) ) )
  4080. {
  4081. if( pafW->dwSize != cbX(DIACTIONFORMATW) )
  4082. {
  4083. D( RPF("IDirectInputDevice::%s: Invalid DIACTIONFORMAT.dwSize 0x%08x",
  4084. s_szProc, pafW->dwSize ); )
  4085. hres = E_INVALIDARG;
  4086. }
  4087. else
  4088. {
  4089. hres = CDIDev_SetActionMapCore( _thisPvNm( pdidW, ddW ),
  4090. pafW, (LPWSTR)lpwszUserName, NULL, dwFlags );
  4091. }
  4092. }
  4093. ExitOleProc();
  4094. return hres;
  4095. }
  4096. /*****************************************************************************
  4097. *
  4098. * @doc INTERNAL
  4099. *
  4100. * @method HRESULT | IDirectInputDevice | SetActionMapA |
  4101. *
  4102. * ANSI version of SetActionMap, see SetActionMapW for details.
  4103. *
  4104. *
  4105. *****************************************************************************/
  4106. STDMETHODIMP CDIDev_SetActionMapA
  4107. (
  4108. PV pdidA,
  4109. LPDIACTIONFORMATA pafA,
  4110. LPCSTR lpszUserName,
  4111. DWORD dwFlags
  4112. )
  4113. {
  4114. HRESULT hres;
  4115. EnterProcR(IDirectInputDevice8A::SetActionMap, (_ "ppAx", pdidA, pafA, lpszUserName, dwFlags));
  4116. if( ( SUCCEEDED( hres = hresPvA( pdidA ) ) )
  4117. && ( SUCCEEDED( hres = CDIDev_ActionMap_IsValidMapObject(
  4118. (LPDIACTIONFORMATW)pafA D(comma s_szProc comma 1) ) ) ) )
  4119. {
  4120. if( pafA->dwSize != cbX(DIACTIONFORMATA) )
  4121. {
  4122. D( RPF("IDirectInputDevice::%s: Invalid DIACTIONFORMAT.dwSize 0x%08x",
  4123. s_szProc, pafA->dwSize ); )
  4124. hres = E_INVALIDARG;
  4125. }
  4126. else
  4127. {
  4128. /*
  4129. * For the sake of the mapper DLLs validation set the size to
  4130. * the UNICODE version. If we ever send this to an external
  4131. * component we should do this differently.
  4132. */
  4133. pafA->dwSize = cbX(DIACTIONFORMATW);
  4134. /*
  4135. * Note, the ANSI user name is passed on as there may be no need
  4136. * to translate it. CDIDev_SetActionMapCore deals with this.
  4137. */
  4138. hres = CDIDev_SetActionMapCore( _thisPvNm( pdidA, ddA ),
  4139. (LPDIACTIONFORMATW)pafA, NULL, (LPSTR)lpszUserName, dwFlags );
  4140. pafA->dwSize = cbX(DIACTIONFORMATA);
  4141. }
  4142. }
  4143. ExitOleProc();
  4144. return hres;
  4145. }
  4146. /*****************************************************************************
  4147. *
  4148. * @doc EXTERNAL
  4149. *
  4150. * @method HRESULT | IDirectInputDevice | GetImageInfo |
  4151. *
  4152. * Retrieves device image information for use in displaying a
  4153. * configuration UI for a single device.
  4154. *
  4155. * @cwrap LPDIRECTINPUTDEVICE | lpDirectInputDevice
  4156. *
  4157. * @parm LPDIDEVICEIMAGEINFOHEADER | pih |
  4158. *
  4159. * Pointer to structure into which the info is retrieved.
  4160. *
  4161. * @returns
  4162. *
  4163. * Returns a COM error code. The following error codes are
  4164. * intended to be illustrative and not necessarily comprehensive.
  4165. *
  4166. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  4167. *
  4168. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: A parameter is invalid.
  4169. *
  4170. * <c DIERR_NOTFOUND>: The device has no image information.
  4171. *
  4172. *****************************************************************************/
  4173. STDMETHODIMP CDIDev_GetImageInfoCore
  4174. (
  4175. PDD this,
  4176. LPDIDEVICEIMAGEINFOHEADERW piih
  4177. )
  4178. {
  4179. HRESULT hres;
  4180. EnterProcI(CDIDev_GetImageInfoCore, (_ "p", piih));
  4181. if( piih->dwSize != cbX( *piih ) )
  4182. {
  4183. D( RPF("IDirectInputDevice::%s: Invalid DIDEVICEIMAGEINFOHEADER.dwSize 0x%08x",
  4184. s_szProc, piih->dwSize ); )
  4185. hres = E_INVALIDARG;
  4186. }
  4187. else if( ( piih->lprgImageInfoArray )
  4188. && ( piih->dwBufferSize < piih->dwSizeImageInfo ) )
  4189. {
  4190. D( RPF("IDirectInputDevice::%s: Invalid DIDEVICEIMAGEINFOHEADER.dwBufferSize 0x%08x",
  4191. s_szProc, piih->dwBufferSize ); )
  4192. hres = E_INVALIDARG;
  4193. }
  4194. else if( piih->dwBufferSize && !piih->lprgImageInfoArray )
  4195. {
  4196. D( RPF("IDirectInputDevice::%s: Invalid DIDEVICEIMAGEINFOHEADERW has dwBufferSize 0x%08x but NULL lprgImageInfoArray",
  4197. s_szProc, piih->dwBufferSize ); )
  4198. hres = E_INVALIDARG;
  4199. }
  4200. else
  4201. {
  4202. LPDIPROPSTRING pdipMapFile;
  4203. if( SUCCEEDED( hres = AllocCbPpv(cbX(*pdipMapFile), &pdipMapFile) ) )
  4204. {
  4205. pdipMapFile->diph.dwSize = cbX(DIPROPSTRING);
  4206. pdipMapFile->diph.dwHeaderSize = cbX(DIPROPHEADER);
  4207. pdipMapFile->diph.dwObj = 0;
  4208. pdipMapFile->diph.dwHow = DIPH_DEVICE;
  4209. /*
  4210. * Must have an IHV file for image info
  4211. */
  4212. hres = CDIDev_GetPropertyW( &this->ddW, DIPROP_MAPFILE, &pdipMapFile->diph );
  4213. if( SUCCEEDED( hres ) )
  4214. {
  4215. /*
  4216. * ISSUE-2001/03/29-timgill workaraound code needs to be removed
  4217. * Initializing this to zero works around most of 34453
  4218. * Remove when that is fixed in DIMap.dll
  4219. */
  4220. piih->dwBufferUsed = 0;
  4221. hres = this->pMS->lpVtbl->GetImageInfo( this->pMS, &this->guid, pdipMapFile->wsz, piih );
  4222. if( SUCCEEDED( hres ) )
  4223. {
  4224. piih->dwcButtons = this->dc3.dwButtons;
  4225. piih->dwcAxes = this->dc3.dwAxes;
  4226. piih->dwcPOVs = this->dc3.dwPOVs;
  4227. AssertF( ( piih->dwBufferSize == 0 )
  4228. || ( piih->dwBufferSize >= piih->dwBufferUsed ) );
  4229. }
  4230. else
  4231. {
  4232. /*
  4233. * Use the same return code for all internal DIMap errors
  4234. */
  4235. if( ( HRESULT_FACILITY( hres ) == FACILITY_ITF )
  4236. && ( HRESULT_CODE( hres ) > 0x0600 ) )
  4237. {
  4238. AssertF( HRESULT_CODE( hres ) < 0x0680 );
  4239. RPF( "Internal GetImageInfo error 0x%08x", hres );
  4240. hres = DIERR_MAPFILEFAIL;
  4241. }
  4242. }
  4243. }
  4244. else
  4245. {
  4246. /*
  4247. * Use the same return code for all forms of not found
  4248. */
  4249. hres = DIERR_NOTFOUND;
  4250. }
  4251. FreePv( pdipMapFile );
  4252. }
  4253. }
  4254. #ifdef DEBUG
  4255. ExitOleProc();
  4256. #endif
  4257. return hres;
  4258. }
  4259. STDMETHODIMP CDIDev_GetImageInfoW
  4260. (
  4261. PV pdidW,
  4262. LPDIDEVICEIMAGEINFOHEADERW piih
  4263. )
  4264. {
  4265. HRESULT hres;
  4266. EnterProcR(IDirectInputDevice8W::GetImageInfo, (_ "pp", pdidW, piih));
  4267. if( SUCCEEDED(hres = hresPvW( pdidW ) )
  4268. && SUCCEEDED(hres = hresFullValidWriteNoScramblePxCb( piih, *piih, 1 ) ) )
  4269. {
  4270. ScrambleBuf( &piih->dwcViews, cbX( piih->dwcViews ) );
  4271. ScrambleBuf( &piih->dwcButtons, cbX( piih->dwcButtons ) );
  4272. ScrambleBuf( &piih->dwcAxes, cbX( piih->dwcAxes ) );
  4273. ScrambleBuf( &piih->dwBufferUsed, cbX( piih->dwBufferUsed ) );
  4274. if( piih->dwSizeImageInfo != cbX( *piih->lprgImageInfoArray ) )
  4275. {
  4276. D( RPF("IDirectInputDevice::%s: Invalid DIDEVICEIMAGEINFOHEADERW.dwSizeImageInfo 0x%08x",
  4277. s_szProc, piih->dwSizeImageInfo ); )
  4278. hres = E_INVALIDARG;
  4279. }
  4280. else if( SUCCEEDED(hres = hresFullValidWriteLargePvCb(
  4281. piih->lprgImageInfoArray, piih->dwBufferSize, 1 ) ) )
  4282. {
  4283. PDD this;
  4284. this = _thisPvNm(pdidW, ddW);
  4285. hres = CDIDev_GetImageInfoCore( this, piih );
  4286. }
  4287. }
  4288. ExitOleProc();
  4289. return hres;
  4290. }
  4291. STDMETHODIMP CDIDev_GetImageInfoA
  4292. (
  4293. PV pdidA,
  4294. LPDIDEVICEIMAGEINFOHEADERA piih
  4295. )
  4296. {
  4297. HRESULT hres;
  4298. EnterProcR(IDirectInputDevice8A::GetImageInfo, (_ "pp", pdidA, piih));
  4299. if( SUCCEEDED(hres = hresPvA( pdidA ) )
  4300. && SUCCEEDED(hres = hresFullValidWriteNoScramblePxCb( piih, *piih, 1 ) ) )
  4301. {
  4302. ScrambleBuf( &piih->dwcViews, cbX( piih->dwcViews ) );
  4303. ScrambleBuf( &piih->dwcButtons, cbX( piih->dwcButtons ) );
  4304. ScrambleBuf( &piih->dwcAxes, cbX( piih->dwcAxes ) );
  4305. ScrambleBuf( &piih->dwBufferUsed, cbX( piih->dwBufferUsed ) );
  4306. if( piih->dwSizeImageInfo != cbX( *piih->lprgImageInfoArray ) )
  4307. {
  4308. D( RPF("IDirectInputDevice::%s: Invalid DIDEVICEIMAGEINFOHEADERA.dwSizeImageInfo 0x%08x",
  4309. s_szProc, piih->dwSizeImageInfo ); )
  4310. hres = E_INVALIDARG;
  4311. }
  4312. else if( SUCCEEDED(hres = hresFullValidWriteLargePvCb(
  4313. piih->lprgImageInfoArray, piih->dwBufferSize, 1 ) ) )
  4314. {
  4315. PDD this;
  4316. DIDEVICEIMAGEINFOHEADERW ihPrivate;
  4317. ihPrivate.dwSize = cbX( ihPrivate );
  4318. ihPrivate.dwSizeImageInfo = cbX( *ihPrivate.lprgImageInfoArray );
  4319. ihPrivate.dwBufferSize = cbX( *ihPrivate.lprgImageInfoArray )
  4320. * ( piih->dwBufferSize / cbX( *piih->lprgImageInfoArray ) );
  4321. hres = AllocCbPpv( ihPrivate.dwBufferSize, &ihPrivate.lprgImageInfoArray );
  4322. if( SUCCEEDED( hres ) )
  4323. {
  4324. this = _thisPvNm(pdidA, ddA);
  4325. hres = CDIDev_GetImageInfoCore( this, &ihPrivate );
  4326. if( SUCCEEDED( hres ) )
  4327. {
  4328. LPDIDEVICEIMAGEINFOW piiW;
  4329. LPDIDEVICEIMAGEINFOA piiA = piih->lprgImageInfoArray;
  4330. CAssertF( cbX( *piiA ) - cbX( piiA->tszImagePath ) == cbX( *piiW ) - cbX( piiW->tszImagePath ) );
  4331. CAssertF( FIELD_OFFSET( DIDEVICEIMAGEINFOA, tszImagePath ) == 0 );
  4332. CAssertF( FIELD_OFFSET( DIDEVICEIMAGEINFOW, tszImagePath ) == 0 );
  4333. CAssertF( FIELD_OFFSET( DIDEVICEIMAGEINFOW, dwFlags ) == cbX( piiW->tszImagePath ) );
  4334. if(ihPrivate.lprgImageInfoArray)
  4335. {
  4336. for( piiW = ihPrivate.lprgImageInfoArray;
  4337. (PBYTE)piiW < (PBYTE)ihPrivate.lprgImageInfoArray + ihPrivate.dwBufferUsed;
  4338. piiW++ )
  4339. {
  4340. UToA( piiA->tszImagePath, cbX( piiA->tszImagePath ), piiW->tszImagePath );
  4341. memcpy( (PV)&piiA->dwFlags, (PV)&piiW->dwFlags,
  4342. cbX( *piiA ) - cbX( piiA->tszImagePath ) );
  4343. piiA++;
  4344. }
  4345. }
  4346. piih->dwBufferUsed = cbX( *piih->lprgImageInfoArray )
  4347. * ( ihPrivate.dwBufferUsed / cbX( *ihPrivate.lprgImageInfoArray ) );
  4348. piih->dwcViews = ihPrivate.dwcViews;
  4349. piih->dwcButtons = ihPrivate.dwcButtons;
  4350. piih->dwcAxes = ihPrivate.dwcAxes;
  4351. piih->dwcPOVs = ihPrivate.dwcPOVs;
  4352. }
  4353. FreePv( ihPrivate.lprgImageInfoArray );
  4354. }
  4355. }
  4356. }
  4357. ExitOleProc();
  4358. return hres;
  4359. }
  4360. /*****************************************************************************
  4361. *
  4362. * @doc EXTERNAL
  4363. *
  4364. * @method HRESULT | IDirectInputDevice | GetDeviceState |
  4365. *
  4366. * Obtains instantaneous data from the DirectInput device.
  4367. *
  4368. * Before device data can be obtained, the data format must
  4369. * be set via <mf IDirectInputDevice::SetDataFormat>, and
  4370. * the device must be acquired via
  4371. * <mf IDirectInputDevice::Acquire>.
  4372. *
  4373. * @cwrap LPDIRECTINPUTDEVICE | lpDirectInputDevice
  4374. *
  4375. * @parm DWORD | cbData |
  4376. *
  4377. * The size of the buffer pointed to by <p lpvData>, in bytes.
  4378. *
  4379. * @parm OUT LPVOID | lpvData |
  4380. *
  4381. * Points to a structure that receives the current state
  4382. * of the device.
  4383. * The format of the data is established by a prior call
  4384. * to <mf IDirectInputDevice::SetDataFormat>.
  4385. *
  4386. * @returns
  4387. *
  4388. * Returns a COM error code. The following error codes are
  4389. * intended to be illustrative and not necessarily comprehensive.
  4390. *
  4391. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  4392. *
  4393. * <c E_PENDING>: The device does not have data yet.
  4394. * Some devices (such as USB joysticks) require a delay
  4395. * between the time the device is turned on and the time
  4396. * the device begins sending data. During this "warm-up" time,
  4397. * <mf IDirectInputDevice::GetDeviceState> will return
  4398. * <c E_PENDING>. When data becomes available, the event
  4399. * notification handle will be signalled.
  4400. *
  4401. * <c DIERR_NOTACQUIRED>: The device is not acquired.
  4402. *
  4403. * <c DIERR_INPUTLOST>: Access to the device has been
  4404. * interrupted. The application should re-acquire the
  4405. * device.
  4406. *
  4407. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: The
  4408. * <p lpvData> parameter is not a valid pointer or
  4409. * the <p cbData> parameter does not match the data size
  4410. * set by a previous call to <mf IDirectInputDevice::SetDataFormat>.
  4411. *
  4412. *****************************************************************************/
  4413. extern STDMETHODIMP CDIDev_Acquire(PV pdd _THAT);
  4414. STDMETHODIMP
  4415. CDIDev_GetDeviceState(PV pdd, DWORD cbDataSize, LPVOID pvData _THAT)
  4416. {
  4417. HRESULT hres;
  4418. PDD this;
  4419. EnterProcR(IDirectInputDevice8::GetDeviceState, (_ "pp", pdd, pvData));
  4420. /*
  4421. * Note that we do not validate the parameters.
  4422. * The reason is that GetDeviceState is an inner loop function,
  4423. * so it should be as fast as possible.
  4424. */
  4425. #ifdef XDEBUG
  4426. hresPvT(pdd);
  4427. hresFullValidWritePvCb(pvData, cbDataSize, 1);
  4428. #endif
  4429. this = _thisPv(pdd);
  4430. /*
  4431. * Must protect with the critical section to prevent somebody from
  4432. * unacquiring while we're reading.
  4433. */
  4434. CDIDev_EnterCrit(this);
  4435. /*
  4436. * Reacquire is not allowed until after Win98 SE, see OSR Bug # 89958
  4437. */
  4438. if ( this->diHacks.fReacquire &&
  4439. !this->fAcquired && (this->fOnceAcquired || this->fOnceForcedUnacquired) )
  4440. {
  4441. if ( SUCCEEDED( CDIDev_Acquire(pdd THAT_) ) ) {
  4442. // 7/18/2000(a-JiTay): IA64: Use %p format specifier for 32/64-bit pointers.
  4443. RPF(" DirectInput: Auto acquired (0x%p)", pdd);
  4444. }
  4445. }
  4446. #ifdef WINNT
  4447. if( this->fUnacquiredWhenIconic && !IsIconic(this->hwnd) ) {
  4448. if ( SUCCEEDED( CDIDev_Acquire(pdd THAT_) ) ) {
  4449. this->fUnacquiredWhenIconic = 0;
  4450. RPF(" DirectInput: Auto acquired device (0x%p) after being iconic. ", pdd);
  4451. }
  4452. }
  4453. #endif
  4454. if ( this->fAcquired ) {
  4455. AssertF(this->pdix); /* Acquire shouldn't let you get this far */
  4456. AssertF(this->GetState);
  4457. AssertF(this->GetDeviceState);
  4458. AssertF(this->pdcb);
  4459. if ( this->dwDataSize == cbDataSize ) {
  4460. #ifndef DEBUG_STICKY
  4461. hres = this->GetState(this, pvData);
  4462. #else
  4463. PBYTE pbDbg;
  4464. TCHAR tszDbg[80];
  4465. hres = this->GetState(this, pvData);
  4466. for( pbDbg=(PBYTE)pvData; pbDbg<((PBYTE)pvData+cbDataSize); pbDbg++ )
  4467. {
  4468. if( *pbDbg )
  4469. {
  4470. wsprintf( tszDbg, TEXT("GotState @ 0x%02x, 0x%02x\r\n"), pbDbg-(PBYTE)pvData, *pbDbg );
  4471. OutputDebugString( tszDbg );
  4472. }
  4473. }
  4474. #endif /* DEBUG_STICKY */
  4475. if ( SUCCEEDED(hres) ) {
  4476. UINT idw;
  4477. AssertF(hres == S_OK);
  4478. /*
  4479. * Icky POV hack for apps that don't check if they have
  4480. * a POV before reading from it.
  4481. */
  4482. for ( idw = 0; idw < this->cdwPOV; idw++ ) {
  4483. DWORD UNALIGNED *pdw = pvAddPvCb(pvData, this->rgdwPOV[idw]);
  4484. *pdw = JOY_POVCENTERED;
  4485. }
  4486. hres = S_OK;
  4487. } else if ( hres == DIERR_INPUTLOST ) {
  4488. RPF("%s: Input lost", s_szProc);
  4489. CDIDev_InternalUnacquire(this);
  4490. hres = DIERR_INPUTLOST;
  4491. }
  4492. } else {
  4493. RPF("ERROR %s: arg %d: invalid value", s_szProc, 1);
  4494. hres = E_INVALIDARG;
  4495. }
  4496. } else {
  4497. hres = this->hresNotAcquired;
  4498. }
  4499. if ( FAILED(hres) ) {
  4500. ScrambleBuf(pvData, cbDataSize);
  4501. }
  4502. CDIDev_LeaveCrit(this);
  4503. ExitOleProc();
  4504. return hres;
  4505. }
  4506. /*****************************************************************************
  4507. *
  4508. * @doc INTERNAL
  4509. *
  4510. * @method void | IDirectInputDevice | CookDeviceData |
  4511. *
  4512. * Cook device data that was recently obtained from the
  4513. * device buffer.
  4514. *
  4515. * Right now, only the joystick device requires cooking,
  4516. * and nobody in their right mind uses buffered joystick
  4517. * data, and the joystick has only a few objects, so we
  4518. * can afford to be slow on this.
  4519. *
  4520. * @cwrap LPDIRECTINPUTDEVICE | lpDirectInputDevice
  4521. *
  4522. * @parm DWORD | cdod |
  4523. *
  4524. * Number of objects to cook.
  4525. *
  4526. * @parm LPDIDEVICEOBJECTDATA | rgdod |
  4527. *
  4528. * Array of object data to cook. The dwOfs are really
  4529. * device object indexes (relative to the device format).
  4530. * After calling the callback, we convert them into
  4531. * application data format offsets.
  4532. *
  4533. * @returns
  4534. *
  4535. * None.
  4536. *
  4537. *****************************************************************************/
  4538. void INTERNAL
  4539. CDIDev_CookDeviceData(PDD this, DWORD cdod, LPDIDEVICEOBJECTDATA rgdod)
  4540. {
  4541. EnterProc(IDirectInputDevice8::CookDeviceData,
  4542. (_ "pxp", this, cdod, rgdod));
  4543. AssertF(this->fCook);
  4544. /*
  4545. * Relative data does not need to be cooked by the callback.
  4546. */
  4547. if( ( this->pvi->fl & VIFL_RELATIVE ) == 0 )
  4548. {
  4549. this->pdcb->lpVtbl->CookDeviceData(this->pdcb, cdod, rgdod);
  4550. }
  4551. /*
  4552. * Step through array converting to application data format offsets
  4553. * including adding the uAppData
  4554. */
  4555. for( ; cdod; cdod--,rgdod++ )
  4556. {
  4557. rgdod->uAppData = this->pdix[rgdod->dwOfs].uAppData;
  4558. rgdod->dwOfs = this->pdix[rgdod->dwOfs].dwOfs;
  4559. }
  4560. ExitProc();
  4561. }
  4562. /*****************************************************************************
  4563. *
  4564. * @doc INTERNAL
  4565. *
  4566. * @struct SOMEDEVICEDATA |
  4567. *
  4568. * Instance data used by <mf IDirectInputDevice::GetSomeDeviceData>.
  4569. *
  4570. * @field DWORD | celtIn |
  4571. *
  4572. * Number of elements remaining in output buffer.
  4573. *
  4574. * @field PDOD | rgdod |
  4575. *
  4576. * Output buffer for data elements, or <c NULL> if
  4577. * elements should be discarded.
  4578. *
  4579. * @field DWORD | celtOut |
  4580. *
  4581. * Number of elements actually copied (so far).
  4582. *
  4583. *****************************************************************************/
  4584. typedef struct SOMEDEVICEDATA {
  4585. DWORD celtIn;
  4586. PDOD rgdod;
  4587. DWORD celtOut;
  4588. } SOMEDEVICEDATA, *PSOMEDEVICEDATA;
  4589. /*****************************************************************************
  4590. *
  4591. * @doc INTERNAL
  4592. *
  4593. * @method PDOD | IDirectInputDevice | GetSomeDeviceData |
  4594. *
  4595. * Obtains a small amount of
  4596. * buffered data from the DirectInput device.
  4597. *
  4598. * @cwrap LPDIRECTINPUTDEVICE | lpDirectInputDevice
  4599. *
  4600. * @parm PDOD | pdod |
  4601. *
  4602. * First element to copy.
  4603. *
  4604. * @parm DWORD | celt |
  4605. *
  4606. * Maximum number of elements to copy.
  4607. *
  4608. * @parm PSOMEDEVICEDATA | psdd |
  4609. *
  4610. * Structure describing the state of the ongoing
  4611. * <mf IDirectInputDevice::GetDeviceData>.
  4612. *
  4613. * @returns
  4614. *
  4615. * Returns a pointer to the first uncopied item.
  4616. *
  4617. *****************************************************************************/
  4618. LPDIDEVICEOBJECTDATA_DX3 INTERNAL
  4619. CDIDev_GetSomeDeviceData
  4620. (
  4621. PDD this,
  4622. LPDIDEVICEOBJECTDATA_DX3 pdod,
  4623. DWORD celt,
  4624. PSOMEDEVICEDATA psdd
  4625. )
  4626. {
  4627. #ifdef XDEBUG
  4628. DWORD cCopied;
  4629. #endif
  4630. EnterProc(IDirectInputDevice8::GetSomeDeviceData,
  4631. (_ "ppxx", this, pdod, celt, psdd->celtIn));
  4632. /*
  4633. * Copy as many elements as fit, but not more than exist
  4634. * in the output buffer.
  4635. */
  4636. if ( celt > psdd->celtIn ) {
  4637. celt = psdd->celtIn;
  4638. }
  4639. #ifdef XDEBUG
  4640. cCopied = celt;
  4641. #endif
  4642. /*
  4643. * Copy the elements (if requested) and update the state.
  4644. * Note that celt might be zero.
  4645. */
  4646. psdd->celtOut += celt;
  4647. psdd->celtIn -= celt;
  4648. if( psdd->rgdod )
  4649. {
  4650. LPDIDEVICEOBJECTDATA pdod8;
  4651. pdod8 = psdd->rgdod;
  4652. if( this->fCook )
  4653. {
  4654. /*
  4655. * For a cooked device, leave the offset untranslated so that it
  4656. * can be used to find the appropriate calibration data.
  4657. */
  4658. for( ; celt ; celt-- )
  4659. {
  4660. pdod8->dwOfs = pdod->dwOfs;
  4661. pdod8->dwData = pdod->dwData;
  4662. pdod8->dwTimeStamp = pdod->dwTimeStamp;
  4663. pdod8->dwSequence = pdod->dwSequence;
  4664. pdod++;
  4665. pdod8++;
  4666. }
  4667. }
  4668. else
  4669. {
  4670. for( ; celt ; celt-- )
  4671. {
  4672. pdod8->dwOfs = this->pdix[pdod->dwOfs].dwOfs;
  4673. pdod8->uAppData = this->pdix[pdod->dwOfs].uAppData;
  4674. pdod8->dwData = pdod->dwData;
  4675. pdod8->dwTimeStamp = pdod->dwTimeStamp;
  4676. pdod8->dwSequence = pdod->dwSequence;
  4677. pdod++;
  4678. pdod8++;
  4679. }
  4680. }
  4681. psdd->rgdod = pdod8;
  4682. }
  4683. else
  4684. {
  4685. pdod += celt;
  4686. }
  4687. if ( pdod == this->pvi->pEnd ) {
  4688. pdod = this->pvi->pBuffer;
  4689. }
  4690. ExitProcX(cCopied);
  4691. return pdod;
  4692. }
  4693. /*
  4694. * Keep GetDeviceData, SendDeviceData and Poll in sqflDev
  4695. */
  4696. #undef sqfl
  4697. #define sqfl sqflDev
  4698. /*****************************************************************************
  4699. *
  4700. * @doc EXTERNAL
  4701. *
  4702. * @method HRESULT | IDirectInputDevice | GetDeviceData |
  4703. *
  4704. * Obtains buffered data from the DirectInput device.
  4705. *
  4706. * DirectInput devices are, by default, unbuffered. To
  4707. * turn on buffering, you must set the buffer size
  4708. * via <mf IDirectInputDevice::SetProperty>, setting the
  4709. * <c DIPROP_BUFFERSIZE> property to the desired size
  4710. * of the input buffer.
  4711. *
  4712. * Before device data can be obtained, the data format must
  4713. * be set via <mf IDirectInputDevice::SetDataFormat>, and
  4714. * the device must be acquired via
  4715. * <mf IDirectInputDevice::Acquire>.
  4716. *
  4717. * @cwrap LPDIRECTINPUTDEVICE | lpDirectInputDevice
  4718. *
  4719. * @parm DWORD | cbObjectData |
  4720. *
  4721. * The size of a single <t DIDEVICEOBJECTDATA> structure in bytes.
  4722. *
  4723. * @parm OUT LPDIDEVICEOBJECTDATA | rgdod |
  4724. *
  4725. * Array of <t DIDEVICEOBJECTDATA> structures to receive
  4726. * the buffered data. It must consist of
  4727. * *<p pdwInOut> elements.
  4728. *
  4729. * If this parameter is <c NULL>, then the buffered data is
  4730. * not stored anywhere, but all other side-effects take place.
  4731. *
  4732. * @parm INOUT LPDWORD | pdwInOut |
  4733. *
  4734. * On entry, contains the number of elements in the array
  4735. * pointed to by <p rgdod>. On exit, contains the number
  4736. * of elements actually obtained.
  4737. *
  4738. * @parm DWORD | fl |
  4739. *
  4740. * Flags which control the manner in which data is obtained.
  4741. * It may be zero or more of the following flags:
  4742. *
  4743. * <c DIGDD_PEEK>: Do not remove the items from the buffer.
  4744. * A subsequent <mf IDirectInputDevice::GetDeviceData> will
  4745. * read the same data. Normally, data is removed from the
  4746. * buffer after it is read.
  4747. *
  4748. ;begin_internal dx4
  4749. * <c DIGDD_RESIDUAL>: Read data from the device buffer
  4750. * even if the device is not acquired. Normally, attempting
  4751. * to read device data from an unacquired device will return
  4752. * <c DIERR_NOTACQUIRED> or <c DIERR_INPUTLOST>.
  4753. ;end_internal dx4
  4754. *
  4755. * @returns
  4756. *
  4757. * <c DI_OK> = <c S_OK>: All data were retrieved
  4758. * successfully. Note that the application needs to check
  4759. * the output value of *<p pdwInOut> to determine whether
  4760. * and how much data was retrieved: The value may be zero,
  4761. * indicating that the buffer was empty.
  4762. *
  4763. * <c DI_BUFFEROVERFLOW> = <c S_FALSE>: Some data
  4764. * were retrieved successfully, but some data were lost
  4765. * because the device's buffer size was not large enough.
  4766. * The application should retrieve buffered data more frequently
  4767. * or increase the device buffer size. This status code is
  4768. * returned only on the first <mf IDirectInput::GetDeviceData>
  4769. * call after the buffer has overflowed. Note that this is
  4770. * a success status code.
  4771. *
  4772. * <c DIERR_NOTACQUIRED>: The device is not acquired.
  4773. *
  4774. * <c DIERR_INPUTLOST>: Access to the device has been
  4775. * interrupted. The application should re-acquire the
  4776. * device.
  4777. *
  4778. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: One or more
  4779. * parameters was invalid. A common cause for this is
  4780. * neglecting to set a buffer size.
  4781. *
  4782. * <c DIERR_NOTBUFFERED>: The device is not buffered.
  4783. * Set the <c DIPROP_BUFFERSIZE> property to enable buffering.
  4784. *
  4785. * @ex
  4786. *
  4787. * The following sample reads up to ten buffered data elements,
  4788. * removing them from the device buffer as they are read.
  4789. *
  4790. * |
  4791. *
  4792. * DIDEVICEOBJECTDATA rgdod[10];
  4793. * DWORD dwItems = 10;
  4794. * hres = IDirectInputDevice_GetDeviceData(
  4795. * pdid,
  4796. * sizeof(DIDEVICEOBJECTDATA),
  4797. * rgdod,
  4798. * &dwItems,
  4799. * 0);
  4800. * if (SUCCEEDED(hres)) {
  4801. * // Buffer successfully flushed.
  4802. * // dwItems = number of elements flushed
  4803. * if (hres == DI_BUFFEROVERFLOW) {
  4804. * // Buffer had overflowed.
  4805. * }
  4806. * }
  4807. *
  4808. *
  4809. *
  4810. *
  4811. * @ex
  4812. *
  4813. * If you pass <c NULL> for the <p rgdod> and request an
  4814. * infinite number of items, this has the effect of flushing
  4815. * the buffer and returning the number of items that were
  4816. * flushed.
  4817. *
  4818. * |
  4819. *
  4820. * dwItems = INFINITE;
  4821. * hres = IDirectInputDevice_GetDeviceData(
  4822. * pdid,
  4823. * sizeof(DIDEVICEOBJECTDATA),
  4824. * NULL,
  4825. * &dwItems,
  4826. * 0);
  4827. * if (SUCCEEDED(hres)) {
  4828. * // Buffer successfully flushed.
  4829. * // dwItems = number of elements flushed
  4830. * if (hres == DI_BUFFEROVERFLOW) {
  4831. * // Buffer had overflowed.
  4832. * }
  4833. * }
  4834. *
  4835. * @ex
  4836. *
  4837. * If you pass <c NULL> for the <p rgdod>, request an
  4838. * infinite number of items, and ask that the data not be
  4839. * removed from the device buffer, this has the effect of
  4840. * querying for the number of elements in the device buffer.
  4841. *
  4842. * |
  4843. *
  4844. * dwItems = INFINITE;
  4845. * hres = IDirectInputDevice_GetDeviceData(
  4846. * pdid,
  4847. * sizeof(DIDEVICEOBJECTDATA),
  4848. * NULL,
  4849. * &dwItems,
  4850. * DIGDD_PEEK);
  4851. * if (SUCCEEDED(hres)) {
  4852. * // dwItems = number of elements in buffer
  4853. * if (hres == DI_BUFFEROVERFLOW) {
  4854. * // Buffer overflow occurred; not all data
  4855. * // were successfully captured.
  4856. * }
  4857. * }
  4858. *
  4859. * @ex
  4860. *
  4861. * If you pass <c NULL> for the <p rgdod> and request zero
  4862. * items, this has the effect of querying whether buffer
  4863. * overflow has occurred.
  4864. *
  4865. * |
  4866. *
  4867. * dwItems = 0;
  4868. * hres = IDirectInputDevice_GetDeviceData(
  4869. * pdid,
  4870. * sizeof(DIDEVICEOBJECTDATA),
  4871. * NULL,
  4872. * &dwItems,
  4873. * 0);
  4874. * if (hres == DI_BUFFEROVERFLOW) {
  4875. * // Buffer overflow occurred
  4876. * }
  4877. *
  4878. *
  4879. *//**************************************************************************
  4880. *
  4881. * When reading this code, the following pictures will come in handy.
  4882. *
  4883. *
  4884. * Buffer not wrapped.
  4885. *
  4886. * pBuffer pEnd
  4887. * | |
  4888. * v v
  4889. * +----+----+----+----+----+----+----+----+----+----+----+
  4890. * | | | | | | | | | | | |
  4891. * | | | |data|data|data|data|data| | | |
  4892. * | | | | | | | | | | | |
  4893. * +----+----+----+----+----+----+----+----+----+----+----+
  4894. * ^ ^
  4895. * | |
  4896. * pTail pHead
  4897. *
  4898. *
  4899. * Buffer wrapped.
  4900. *
  4901. * pBuffer pEnd
  4902. * | |
  4903. * v v
  4904. * +----+----+----+----+----+----+----+----+----+----+----+
  4905. * | | | | | | | | | | | |
  4906. * |data|data| | | | | | |data|data|data|
  4907. * | | | | | | | | | | | |
  4908. * +----+----+----+----+----+----+----+----+----+----+----+
  4909. * ^ ^
  4910. * | |
  4911. * pHead pTail
  4912. *
  4913. *
  4914. * Boundary wrap case.
  4915. *
  4916. *
  4917. * pBuffer pEnd
  4918. * | |
  4919. * v v
  4920. * +----+----+----+----+----+----+----+----+----+----+----+
  4921. * | | | | | | | | | | | |
  4922. * | | | | | | |data|data|data|data|data|
  4923. * | | | | | | | | | | | |
  4924. * +----+----+----+----+----+----+----+----+----+----+----+
  4925. * ^ ^
  4926. * | |
  4927. * pHead pTail
  4928. *
  4929. *
  4930. * Note! At no point is pTail == pEnd or pHead == pEnd.
  4931. *
  4932. *****************************************************************************/
  4933. STDMETHODIMP
  4934. CDIDev_GetDeviceData(PV pdd, DWORD cbdod, PDOD rgdod,
  4935. LPDWORD pdwInOut, DWORD fl _THAT)
  4936. {
  4937. HRESULT hres;
  4938. PDD this;
  4939. SOMEDEVICEDATA sdd;
  4940. EnterProcR(IDirectInputDevice8::GetDeviceData,
  4941. (_ "pxpxx", pdd, cbdod, rgdod,
  4942. IsBadReadPtr(pdwInOut, cbX(DWORD)) ? 0 : *pdwInOut, fl));
  4943. /*
  4944. * Note that we do not validate the parameters.
  4945. * The reason is that GetDeviceData is an inner loop function,
  4946. * so it should be as fast as possible.
  4947. *
  4948. * Note also that it is legal to get device data after the device
  4949. * has been unacquired. This lets you "turn on the faucet" for
  4950. * a short period of time, and then parse the data out later.
  4951. */
  4952. this = _thisPv(pdd);
  4953. #ifdef XDEBUG
  4954. hresPvT(pdd);
  4955. if ( IsBadWritePtr(pdwInOut, cbX(*pdwInOut)) ) {
  4956. RPF("ERROR %s: arg %d: invalid value; crash soon", s_szProc, 3);
  4957. }
  4958. #endif
  4959. if( cbdod == cbX(DOD) )
  4960. {
  4961. #ifdef XDEBUG
  4962. /*
  4963. * Only check the buffer if the size is correct otherwise
  4964. * we can smash the stack of the caller when we've already
  4965. * detected the error.
  4966. */
  4967. if ( rgdod ) {
  4968. hresFullValidWritePvCb(rgdod, *pdwInOut * cbdod, 2);
  4969. }
  4970. #endif
  4971. /*
  4972. * Must protect with the critical section to prevent somebody from
  4973. * acquiring/unacquiring or changing the data format or calling
  4974. * another GetDeviceData while we're reading. (We must be serialized.)
  4975. */
  4976. CDIDev_EnterCrit(this);
  4977. AssertF(CDIDev_IsConsistent(this));
  4978. if ( SUCCEEDED(hres = hresFullValidFl(fl, DIGDD_VALID, 4)) ) {
  4979. if ( this->celtBuf ) {
  4980. /*
  4981. * Don't try to read more than there possibly could be.
  4982. * This avoids overflow conditions in case celtIn is
  4983. * some absurdly huge number.
  4984. */
  4985. sdd.celtIn = *pdwInOut;
  4986. sdd.celtOut = 0;
  4987. if ( sdd.celtIn > this->celtBuf ) {
  4988. sdd.celtIn = this->celtBuf;
  4989. }
  4990. sdd.rgdod = rgdod;
  4991. /*
  4992. * For this version of DirectInput, we do not allow
  4993. * callbacks to implement their own GetDeviceData.
  4994. */
  4995. if ( this->pvi ) {
  4996. /*
  4997. * Reacquire is not allowed until after Win98 SE, see OSR Bug # 89958
  4998. */
  4999. if ( this->diHacks.fReacquire &&
  5000. !this->fAcquired && (this->fOnceAcquired || this->fOnceForcedUnacquired) )
  5001. {
  5002. if ( SUCCEEDED( CDIDev_Acquire(pdd THAT_) ) ) {
  5003. // 7/18/2000(a-JiTay): IA64: Use %p format specifier for 32/64-bit pointers.
  5004. RPF(" DirectInput: Auto acquired device (0x%p)", pdd);
  5005. }
  5006. }
  5007. #ifdef WINNT
  5008. if( this->fUnacquiredWhenIconic && !IsIconic(this->hwnd) ) {
  5009. if ( SUCCEEDED( CDIDev_Acquire(pdd THAT_) ) ) {
  5010. this->fUnacquiredWhenIconic = 0;
  5011. RPF(" DirectInput: Auto acquired device (0x%p) after being iconic. ", pdd);
  5012. }
  5013. }
  5014. #endif
  5015. if ( (this->fAcquired && (this->pvi->fl & VIFL_ACQUIRED)) ||
  5016. (fl & DIGDD_RESIDUAL) ) {
  5017. /*
  5018. * The device object data from the driver is always a
  5019. * DX3 (<DX8) structure
  5020. */
  5021. LPDIDEVICEOBJECTDATA_DX3 pdod, pdodHead;
  5022. DWORD celt;
  5023. /*
  5024. * Snapshot the value of pdodHead, because it can
  5025. * change asynchronously. The other fields won't
  5026. * change unless we ask for them to be changed.
  5027. */
  5028. pdodHead = this->pvi->pHead;
  5029. /*
  5030. * Throughout, pdod points to the first unprocessed
  5031. * element.
  5032. */
  5033. pdod = this->pvi->pTail;
  5034. /*
  5035. * If we are wrapped, handle the initial run.
  5036. */
  5037. if ( pdodHead < this->pvi->pTail ) {
  5038. celt = (DWORD)(this->pvi->pEnd - this->pvi->pTail);
  5039. AssertF(celt);
  5040. pdod = CDIDev_GetSomeDeviceData( this, pdod, celt, &sdd );
  5041. }
  5042. /*
  5043. * Now handle the glob from pdod to pdodHead.
  5044. * Remember, pvi->pdodHead may have changed
  5045. * behind our back; use the cached value to
  5046. * ensure consistency. (If we miss data,
  5047. * it'll show up later.)
  5048. */
  5049. AssertF(fLimpFF(sdd.celtIn, pdodHead >= pdod));
  5050. celt = (DWORD)(pdodHead - pdod);
  5051. if ( celt ) {
  5052. pdod = CDIDev_GetSomeDeviceData( this, pdod, celt, &sdd );
  5053. }
  5054. *pdwInOut = sdd.celtOut;
  5055. if ( !(fl & DIGDD_PEEK) ) {
  5056. this->pvi->pTail = pdod;
  5057. }
  5058. if ( rgdod && sdd.celtOut && this->fCook ) {
  5059. CDIDev_CookDeviceData(this, sdd.celtOut, rgdod );
  5060. }
  5061. CAssertF(S_OK == 0);
  5062. CAssertF(DI_BUFFEROVERFLOW == 1);
  5063. hres = (HRESULT)(UINT_PTR)pvExchangePpvPv(&this->pvi->fOverflow, 0);
  5064. #ifdef DEBUG_STICKY
  5065. if( hres == 1 )
  5066. {
  5067. OutputDebugString( TEXT( "Device buffer overflowed\r\n" ) );
  5068. }
  5069. if( sdd.celtOut )
  5070. {
  5071. PDOD pdoddbg;
  5072. TCHAR tszDbg[80];
  5073. wsprintf( tszDbg, TEXT("GotData %d elements: "), sdd.celtOut );
  5074. OutputDebugString( tszDbg );
  5075. for( pdoddbg=rgdod; pdoddbg<&rgdod[sdd.celtOut]; pdoddbg++ )
  5076. {
  5077. wsprintf( tszDbg, TEXT("0x%02x:x0x%08x "), pdoddbg->dwOfs, pdoddbg->dwData );
  5078. OutputDebugString( tszDbg );
  5079. }
  5080. OutputDebugString( TEXT("\r\n") );
  5081. }
  5082. #endif /* DEBUG_STICKY */
  5083. } else if (this->fAcquired && !(this->pvi->fl & VIFL_ACQUIRED)) {
  5084. RPF("ERROR %s - %s", s_szProc, "input lost");
  5085. hres = DIERR_INPUTLOST;
  5086. CDIDev_InternalUnacquire(this);
  5087. } else {
  5088. RPF("ERROR %s: %s", s_szProc,
  5089. this->hresNotAcquired == DIERR_NOTACQUIRED
  5090. ? "Not acquired" : "Input lost");
  5091. hres = this->hresNotAcquired;
  5092. }
  5093. } else { /* Don't support device-side GetData yet */
  5094. hres = E_NOTIMPL;
  5095. }
  5096. } else { /* Device is not buffered */
  5097. #ifdef XDEBUG
  5098. if ( !this->fNotifiedNotBuffered ) {
  5099. this->fNotifiedNotBuffered = 1;
  5100. RPF("ERROR %s: arg %d: device is not buffered", s_szProc, 0);
  5101. }
  5102. #endif
  5103. hres = DIERR_NOTBUFFERED;
  5104. }
  5105. }
  5106. }
  5107. else
  5108. {
  5109. if( cbdod == cbX(DIDEVICEOBJECTDATA_DX3) )
  5110. {
  5111. RPF("ERROR %s: arg %d: old size, invalid for DX8", s_szProc, 1);
  5112. }
  5113. else
  5114. {
  5115. RPF("ERROR %s: arg %d: invalid value", s_szProc, 1);
  5116. }
  5117. hres = E_INVALIDARG;
  5118. }
  5119. CDIDev_LeaveCrit(this);
  5120. return hres;
  5121. }
  5122. /*****************************************************************************
  5123. *
  5124. * @doc EXTERNAL
  5125. *
  5126. * @method HRESULT | IDirectInputDevice8 | Poll |
  5127. *
  5128. * Retrieves data from polled objects on a DirectInput device.
  5129. * If the device does not require polling, then calling this
  5130. * method has no effect. If a device that requires polling
  5131. * is not polled periodically, no new data will be received
  5132. * from the device.
  5133. *
  5134. * Before a device data can be polled, the data format must
  5135. * be set via <mf IDirectInputDevice::SetDataFormat>, and
  5136. * the device must be acquired via
  5137. * <mf IDirectInputDevice::Acquire>.
  5138. *
  5139. * @cwrap LPDIRECTINPUTDEVICE | lpDirectInputDevice
  5140. *
  5141. * @returns
  5142. *
  5143. * Returns a COM error code. The following error codes are
  5144. * intended to be illustrative and not necessarily comprehensive.
  5145. *
  5146. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  5147. *
  5148. * <c DI_NOEFFECT> = <c S_FALSE>: The device does not require
  5149. * polling.
  5150. *
  5151. * <c DIERR_INPUTLOST>: Access to the device has been
  5152. * interrupted. The application should re-acquire the
  5153. * device.
  5154. *
  5155. * <c DIERR_NOTACQUIRED>: The device is not acquired.
  5156. *
  5157. *****************************************************************************/
  5158. STDMETHODIMP
  5159. CDIDev_Poll(PV pdd _THAT)
  5160. {
  5161. HRESULT hres;
  5162. PDD this;
  5163. EnterProcR(IDirectInputDevice8::Poll, (_ "p", pdd));
  5164. /*
  5165. * Note that we do not validate the parameters.
  5166. * The reason is that Poll is an inner loop function,
  5167. * so it should be as fast as possible.
  5168. */
  5169. #ifdef XDEBUG
  5170. hresPvT(pdd);
  5171. #endif
  5172. this = _thisPv(pdd);
  5173. /*
  5174. * Fast out: If the device doesn't require polling,
  5175. * then don't bother with the critical section or other validation.
  5176. */
  5177. if ( this->fPolledDataFormat ) {
  5178. /*
  5179. * Must protect with the critical section to prevent somebody from
  5180. * unacquiring while we're polling.
  5181. */
  5182. CDIDev_EnterCrit(this);
  5183. if ( this->fAcquired ) {
  5184. hres = this->pdcb->lpVtbl->Poll(this->pdcb);
  5185. } else {
  5186. hres = this->hresNotAcquired;
  5187. }
  5188. CDIDev_LeaveCrit(this);
  5189. } else {
  5190. if ( this->fAcquired ) {
  5191. hres = S_FALSE;
  5192. } else {
  5193. hres = this->hresNotAcquired;
  5194. }
  5195. }
  5196. /*
  5197. * Failing polls are really annoying so don't use ExitOleProc
  5198. */
  5199. if( FAILED( hres ) )
  5200. {
  5201. SquirtSqflPtszV(sqfl | sqflVerbose, TEXT("IDirectInputDevice::Poll failed 0x%08x"), hres );
  5202. }
  5203. ExitProc();
  5204. return hres;
  5205. }
  5206. /*****************************************************************************
  5207. *
  5208. * @doc EXTERNAL
  5209. *
  5210. * @method HRESULT | IDirectInputDevice8 | SendDeviceData |
  5211. *
  5212. * Sends data to the device.
  5213. *
  5214. * Before device data can be sent to a device,
  5215. * the device must be acquired via
  5216. * <mf IDirectInputDevice::Acquire>.
  5217. *
  5218. * Note that no guarantees
  5219. * are made on the order in which the individual data
  5220. * elements are sent. However, data sent by
  5221. * successive calls to
  5222. * <mf IDirectInputDevice8::SendDeviceData>
  5223. * will not be interleaved.
  5224. * Furthermore, if multiple pieces of
  5225. * data are sent to the same object, it is unspecified
  5226. * which actual piece of data is sent.
  5227. *
  5228. * Consider, for example, a device which can be sent
  5229. * data in packets, each packet describing two pieces
  5230. * of information, call them A and B. Suppose the
  5231. * application attempts to send three data elements,
  5232. * "B = 2", "A = 1", and "B = 0".
  5233. *
  5234. * The actual device will be sent a single packet.
  5235. * The "A" field of the packet will contain the value 1,
  5236. * and the "B" field of the packet will be either 2 or 0.
  5237. *
  5238. * If the application wishes the data to be sent to the
  5239. * device exactly as specified, then three calls to
  5240. * <mf IDirectInputDevice8::SendDeviceData> should be
  5241. * performed, each call sending one data element.
  5242. *
  5243. * In response to the first call,
  5244. * the device will be sent a packet where the "A" field
  5245. * is blank and the "B" field contains the value 2.
  5246. *
  5247. * In response to the second call,
  5248. * the device will be sent a packet where the "A" field
  5249. * contains the value 1, and the "B" field is blank.
  5250. *
  5251. * Finally, in response to the third call,
  5252. * the device will be sent a packet where the "A" field
  5253. * is blank and the "B" field contains the value 0.
  5254. *
  5255. *
  5256. *
  5257. * @cwrap LPDIRECTINPUTDEVICE | lpDirectInputDevice
  5258. *
  5259. * @parm DWORD | cbObjectData |
  5260. *
  5261. * The size of a single <t DIDEVICEOBJECTDATA> structure in bytes.
  5262. *
  5263. * @parm IN LPCDIDEVICEOBJECTDATA | rgdod |
  5264. *
  5265. * Array of <t DIDEVICEOBJECTDATA> structures containing
  5266. * the data to send to the device. It must consist of
  5267. * *<p pdwInOut> elements.
  5268. *
  5269. * <y Note>: The <e DIDEVICEOBJECTDATA.dwOfs> field of
  5270. * the <t DIDEVICEOBJECTDATA> structure must contain the
  5271. * device object identifier (as obtained from the
  5272. * <e DIDEVICEOBJECTINSTANCE.dwType> field of the
  5273. * <t DIDEVICEOBJECTINSTANCE> sturcture) for the device
  5274. * object at which the data is directed.
  5275. *
  5276. * Furthermore, the <e DIDEVICEOBJECTDATA.dwTimeStamp>
  5277. * <e DIDEVICEOBJECTDATA.dwSequence> and
  5278. * <e DIDEVICEOBJECTDATA.uAppData> fields are
  5279. * reserved for future use and must be zero.
  5280. *
  5281. * @parm INOUT LPDWORD | pdwInOut |
  5282. *
  5283. * On entry, contains the number of elements in the array
  5284. * pointed to by <p rgdod>. On exit, contains the number
  5285. * of elements actually sent to the device.
  5286. *
  5287. * @parm DWORD | fl |
  5288. *
  5289. * Flags which control the manner in which data is sent.
  5290. * It may consist of zero or more of the following flags:
  5291. *
  5292. * <c DISDD_CONTINUE>: If this flag is set, then
  5293. * the device data sent will be overlaid upon the previously
  5294. * sent device data. Otherwise, the device data sent
  5295. * will start from scratch.
  5296. *
  5297. * For example, suppose a device supports two button outputs,
  5298. * call them A and B.
  5299. * If an application first calls
  5300. * <mf IDirectInputDevice8::SendDeviceData> passing
  5301. * "button A pressed", then
  5302. * a packet of the form "A pressed, B not pressed" will be
  5303. * sent to the device.
  5304. * If an application then calls
  5305. * <mf IDirectInputDevice8::SendDeviceData> passing
  5306. * "button B pressed" and the <c DISDD_CONTINUE> flag, then
  5307. * a packet of the form "A pressed, B pressed" will be
  5308. * sent to the device.
  5309. * However, if the application had not passed the
  5310. * <c DISDD_CONTINUE> flag, then the packet sent to the device
  5311. * would have been "A not pressed, B pressed".
  5312. *
  5313. *
  5314. * @returns
  5315. *
  5316. * Returns a COM error code. The following error codes are
  5317. * intended to be illustrative and not necessarily comprehensive.
  5318. *
  5319. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  5320. *
  5321. * <c DIERR_INPUTLOST>: Access to the device has been
  5322. * interrupted. The application should re-acquire the
  5323. * device.
  5324. *
  5325. * <c DIERR_NOTACQUIRED>: The device is not acquired.
  5326. *
  5327. *****************************************************************************/
  5328. STDMETHODIMP
  5329. CDIDev_SendDeviceData(PV pdd, DWORD cbdod, LPCDIDEVICEOBJECTDATA rgdod,
  5330. LPDWORD pdwInOut, DWORD fl _THAT)
  5331. {
  5332. HRESULT hres;
  5333. PDD this;
  5334. EnterProcR(IDirectInputDevice8::SendDeviceData,
  5335. (_ "pxpxx", pdd, cbdod, rgdod,
  5336. IsBadReadPtr(pdwInOut, cbX(DWORD)) ? 0 : *pdwInOut, fl));
  5337. /*
  5338. * Note that parameter validation is limited as SendDeviceData is
  5339. * intended to be an inner loop function. In practice SendDeviceData is
  5340. * rarely used so speed is not that important.
  5341. */
  5342. #ifdef XDEBUG
  5343. hresPvT(pdd);
  5344. if ( IsBadWritePtr(pdwInOut, cbX(*pdwInOut)) ) {
  5345. RPF("ERROR %s: arg %d: invalid value; crash soon", s_szProc, 3);
  5346. }
  5347. hresFullValidReadPvCb(rgdod, cbX(*pdwInOut) * cbdod, 2);
  5348. #endif
  5349. this = _thisPv(pdd);
  5350. /*
  5351. * Must protect with the critical section to prevent somebody from
  5352. * unacquiring while we're sending data.
  5353. */
  5354. CDIDev_EnterCrit(this);
  5355. if ( SUCCEEDED(hres = hresFullValidFl(fl, DISDD_VALID, 4)) ) {
  5356. if( cbdod == cbX(DOD) )
  5357. {
  5358. #ifdef XDEBUG
  5359. UINT iodDbg;
  5360. LPCDIDEVICEOBJECTDATA pcdod;
  5361. for ( iodDbg = 0, pcdod=rgdod; iodDbg < *pdwInOut; iodDbg++ ) {
  5362. if ( pcdod->dwTimeStamp ) {
  5363. RPF("%s: ERROR: dwTimeStamp must be zero", s_szProc);
  5364. }
  5365. if ( pcdod->dwSequence ) {
  5366. RPF("%s: ERROR: dwSequence must be zero", s_szProc);
  5367. }
  5368. if( pcdod->uAppData ){
  5369. RPF("%s: ERROR: uAppData must be zero", s_szProc);
  5370. }
  5371. pcdod++;
  5372. }
  5373. #endif
  5374. if ( this->fAcquired ) {
  5375. UINT iod;
  5376. LPDIDEVICEOBJECTDATA pdodCopy;
  5377. hres = AllocCbPpv( cbCxX( *pdwInOut, *pdodCopy ), &pdodCopy );
  5378. if( SUCCEEDED( hres ) )
  5379. {
  5380. LPDIDEVICEOBJECTDATA pdod;
  5381. memcpy( pdodCopy, rgdod, cbCxX( *pdwInOut, *pdodCopy ) );
  5382. for( iod=0, pdod=pdodCopy; iod < *pdwInOut; iod++ )
  5383. {
  5384. int iobj = CDIDev_OffsetToIobj(this, pdod->dwOfs);
  5385. pdod->dwOfs = this->df.rgodf[iobj].dwType;
  5386. pdod++;
  5387. }
  5388. hres = this->pdcb->lpVtbl->SendDeviceData(this->pdcb, cbdod,
  5389. pdodCopy, pdwInOut, fl );
  5390. FreePv( pdodCopy );
  5391. }
  5392. } else {
  5393. hres = this->hresNotAcquired;
  5394. }
  5395. } else {
  5396. RPF("ERROR %s: arg %d: invalid value", s_szProc, 1);
  5397. }
  5398. }
  5399. CDIDev_LeaveCrit(this);
  5400. ExitOleProc();
  5401. return hres;
  5402. }
  5403. #undef sqfl
  5404. #define sqfl sqflDf
  5405. /*****************************************************************************
  5406. *
  5407. * @doc INTERNAL
  5408. *
  5409. * @func BOOL | CDIDev_CheckId |
  5410. *
  5411. * Verify that the item has the appropriate type.
  5412. *
  5413. * @parm DWORD | dwId |
  5414. *
  5415. * ID to locate.
  5416. *
  5417. * @parm UINT | fl |
  5418. *
  5419. * Bitmask of flags for things to validate.
  5420. *
  5421. * The <c DEVCO_TYPEMASK> fields describe what type
  5422. * of object we should be locating.
  5423. *
  5424. * The <c DEVCO_ATTRMASK> fields describe the attribute
  5425. * bits that are required.
  5426. *
  5427. *****************************************************************************/
  5428. BOOL INLINE
  5429. CDIDev_CheckId(DWORD dwId, DWORD fl)
  5430. {
  5431. CAssertF(DIDFT_ATTRMASK == DEVCO_ATTRMASK);
  5432. return(dwId & fl & DEVCO_TYPEMASK) &&
  5433. fHasAllBitsFlFl(dwId, fl & DIDFT_ATTRMASK);
  5434. }
  5435. /*****************************************************************************
  5436. *
  5437. * @doc INTERNAL
  5438. *
  5439. * @method int | CDIDev | IdToIobj |
  5440. *
  5441. * Locate an item which matches the specified ID.
  5442. *
  5443. * @cwrap PDD | this
  5444. *
  5445. * @parm DWORD | dwId |
  5446. *
  5447. * ID to locate.
  5448. *
  5449. * @returns
  5450. *
  5451. * Returns the index of the object found, or -1 on error.
  5452. *
  5453. *****************************************************************************/
  5454. int INTERNAL
  5455. CDIDev_IdToIobj(PDD this, DWORD dwId)
  5456. {
  5457. int iobj;
  5458. /* Someday: Perf: Should have xlat table */
  5459. for ( iobj = this->df.dwNumObjs; --iobj >= 0; ) {
  5460. PODF podf = &this->df.rgodf[iobj];
  5461. if ( DIDFT_FINDMATCH(podf->dwType, dwId) ) {
  5462. goto done;
  5463. }
  5464. }
  5465. iobj = -1;
  5466. done:;
  5467. return iobj;
  5468. }
  5469. #if 0
  5470. /*****************************************************************************
  5471. *
  5472. * @doc INTERNAL
  5473. *
  5474. * @method HRESULT | CDIDev | IdToId |
  5475. *
  5476. * Convert a single <t DWORD> from an ID to an ID.
  5477. *
  5478. * This is clearly a very simple operation.
  5479. *
  5480. * It's all validation.
  5481. *
  5482. * @cwrap PDD | this
  5483. *
  5484. * @parm LPDWORD | pdw |
  5485. *
  5486. * Single item to convert.
  5487. *
  5488. * @parm UINT | fl |
  5489. *
  5490. * Bitmask of flags that govern the conversion.
  5491. * The function should look only at
  5492. * <c DEVCO_AXIS> or <c DEVCO_BUTTON>.
  5493. *
  5494. *****************************************************************************/
  5495. HRESULT INTERNAL
  5496. CDIDev_IdToId(PDD this, LPDWORD pdw, UINT fl)
  5497. {
  5498. HRESULT hres;
  5499. int iobj;
  5500. iobj = CDIDev_FindId(this, *pdw, fl);
  5501. if ( iobj >= 0 ) {
  5502. *pdw = this->df.rgodf[iobj].dwType;
  5503. hres = S_OK;
  5504. } else {
  5505. hres = E_INVALIDARG;
  5506. }
  5507. return hres;
  5508. }
  5509. #endif
  5510. /*****************************************************************************
  5511. *
  5512. * @doc INTERNAL
  5513. *
  5514. * @method int | CDIDev | OffsetToIobj |
  5515. *
  5516. * Convert a single <t DWORD> from an offset to an object index.
  5517. *
  5518. * @cwrap PDD | this
  5519. *
  5520. * @parm DWORD | dwOfs |
  5521. *
  5522. * Offset to convert.
  5523. *
  5524. *****************************************************************************/
  5525. int INTERNAL
  5526. CDIDev_OffsetToIobj(PDD this, DWORD dwOfs)
  5527. {
  5528. int iobj;
  5529. AssertF(this->pdix);
  5530. AssertF(this->rgiobj);
  5531. if ( dwOfs < this->dwDataSize ) {
  5532. iobj = this->rgiobj[dwOfs];
  5533. if ( iobj >= 0 ) {
  5534. AssertF(this->pdix[iobj].dwOfs == dwOfs);
  5535. } else {
  5536. AssertF(iobj == -1);
  5537. }
  5538. } else {
  5539. iobj = -1;
  5540. }
  5541. return iobj;
  5542. }
  5543. /*****************************************************************************
  5544. *
  5545. * @doc INTERNAL
  5546. *
  5547. * @method int | CDIDev | IobjToId |
  5548. *
  5549. * Convert an object index to an ID.
  5550. *
  5551. * @cwrap PDD | this
  5552. *
  5553. * @parm int | iobj |
  5554. *
  5555. * Single item to convert.
  5556. *
  5557. *****************************************************************************/
  5558. DWORD INLINE
  5559. CDIDev_IobjToId(PDD this, int iobj)
  5560. {
  5561. AssertF((DWORD)iobj < this->df.dwNumObjs);
  5562. return this->df.rgodf[iobj].dwType;
  5563. }
  5564. /*****************************************************************************
  5565. *
  5566. * @doc INTERNAL
  5567. *
  5568. * @method int | CDIDev | IobjToOffset |
  5569. *
  5570. * Convert an object index to an offset.
  5571. *
  5572. * @cwrap PDD | this
  5573. *
  5574. * @parm int | iobj |
  5575. *
  5576. * Single item to convert.
  5577. *
  5578. *****************************************************************************/
  5579. DWORD INLINE
  5580. CDIDev_IobjToOffset(PDD this, int iobj)
  5581. {
  5582. AssertF((DWORD)iobj < this->df.dwNumObjs);
  5583. AssertF(this->pdix);
  5584. return this->pdix[iobj].dwOfs;
  5585. }
  5586. /*****************************************************************************
  5587. *
  5588. * @doc INTERNAL
  5589. *
  5590. * @method HRESULT | CDIDev | ConvertObjects |
  5591. *
  5592. * Convert between the ways of talking about device gizmos.
  5593. *
  5594. * Since this is used only by the force feedback subsystem,
  5595. * we also barf if the device found does not support
  5596. * force feedback.
  5597. *
  5598. * @cwrap PDD | this
  5599. *
  5600. * @parm UINT | cdw |
  5601. *
  5602. * Number of elements to convert (in-place).
  5603. *
  5604. * @parm LPDWORD | rgdw |
  5605. *
  5606. * Array of elements to convert.
  5607. *
  5608. * @parm UINT | fl |
  5609. *
  5610. * Flags that describe how to do the conversion.
  5611. *
  5612. * <c DEVCO_AXIS> or <c DEVCO_BUTTON> indicate whether
  5613. * the item being converted is an axis or button.
  5614. *
  5615. * <c DEVCO_FROM*> specifies what the existing value is.
  5616. *
  5617. * <c DEVCO_TO*> specifies what the new values should be.
  5618. *
  5619. *****************************************************************************/
  5620. STDMETHODIMP
  5621. CDIDev_ConvertObjects(PDD this, UINT cdw, LPDWORD rgdw, UINT fl)
  5622. {
  5623. HRESULT hres;
  5624. /*
  5625. * Don't let somebody change the data format while we're
  5626. * looking at it.
  5627. */
  5628. CDIDev_EnterCrit(this);
  5629. AssertF((fl & ~DEVCO_VALID) == 0);
  5630. if ( fLimpFF(fl & (DEVCO_FROMOFFSET | DEVCO_TOOFFSET),
  5631. this->pdix && this->rgiobj) ) {
  5632. UINT idw;
  5633. for ( idw = 0; idw < cdw; idw++ ) {
  5634. /*
  5635. * Convert from its source to an object index,
  5636. * validate the object index, then convert to
  5637. * the target.
  5638. */
  5639. int iobj;
  5640. switch ( fl & DEVCO_FROMMASK ) {
  5641. default:
  5642. AssertF(0); /* Huh? */
  5643. case DEVCO_FROMID:
  5644. iobj = CDIDev_IdToIobj(this, rgdw[idw]);
  5645. break;
  5646. case DEVCO_FROMOFFSET:
  5647. iobj = CDIDev_OffsetToIobj(this, rgdw[idw]);
  5648. break;
  5649. }
  5650. if ( iobj < 0 ) {
  5651. hres = E_INVALIDARG; /* Invalid object */
  5652. goto done;
  5653. }
  5654. AssertF((DWORD)iobj < this->df.dwNumObjs);
  5655. if ( !CDIDev_CheckId(this->df.rgodf[iobj].dwType, fl) ) {
  5656. hres = E_INVALIDARG; /* Bad attributes */
  5657. goto done;
  5658. }
  5659. switch ( fl & DEVCO_TOMASK ) {
  5660. default:
  5661. AssertF(0); /* Huh? */
  5662. case DEVCO_TOID:
  5663. rgdw[idw] = CDIDev_IobjToId(this, iobj);
  5664. break;
  5665. case DEVCO_TOOFFSET:
  5666. rgdw[idw] = CDIDev_IobjToOffset(this, iobj);
  5667. break;
  5668. }
  5669. }
  5670. hres = S_OK;
  5671. done:;
  5672. } else {
  5673. RPF("ERROR: Must have a data format to use offsets");
  5674. hres = E_INVALIDARG;
  5675. }
  5676. CDIDev_LeaveCrit(this);
  5677. return hres;
  5678. }