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.

4650 lines
165 KiB

  1. /*****************************************************************************
  2. *
  3. * DIHidIni.c
  4. *
  5. * Copyright (c) 1996 - 2000 Microsoft Corporation. All Rights Reserved.
  6. *
  7. * Abstract:
  8. *
  9. * The initialization-related functions of the HID device callback.
  10. *
  11. * All the HID support is getting kind of bulky, so I've broken
  12. * it out into submodules.
  13. *
  14. * Contents:
  15. *
  16. * CHid_Init
  17. *
  18. *****************************************************************************/
  19. #include "dinputpr.h"
  20. /*****************************************************************************
  21. *
  22. * The sqiffle for this file.
  23. *
  24. *****************************************************************************/
  25. #define sqfl sqflHidIni
  26. /*****************************************************************************
  27. *
  28. * Hid devices are totally arbitrary, so there is nothing static we
  29. * can cook up to describe them. We generate all the information on
  30. * the fly.
  31. *
  32. *****************************************************************************/
  33. /*****************************************************************************
  34. *
  35. * @doc INTERNAL
  36. *
  37. * @func UINT | CHid_LoadCalibrations |
  38. *
  39. * Load calibration information from the registry (or wherever).
  40. * This is done when the device is created, and whenever we
  41. * receive a recalibration message.
  42. *
  43. * @returns
  44. *
  45. * Returns the number of axes we calibrated. This information
  46. * is used during device initialization to see if we need to
  47. * worry about calibration in the future.
  48. *
  49. *****************************************************************************/
  50. UINT EXTERNAL
  51. CHid_LoadCalibrations(PCHID this)
  52. {
  53. UINT uiObj;
  54. UINT uiRc = 0;
  55. /*
  56. * Preinitialize the HIDP_DATA indices to -1 to indicate
  57. * that they aren't there. We must do this before we
  58. * mess with AddDeviceData, which assumes that all the
  59. * indices are properly set up.
  60. */
  61. for(uiObj = 0; uiObj < this->df.dwNumObjs; uiObj++)
  62. {
  63. PJOYRANGECONVERT pjrc = this->rghoc[uiObj].pjrc;
  64. PHIDGROUPCAPS pcaps = this->rghoc[uiObj].pcaps;
  65. if(pjrc && pcaps)
  66. {
  67. LPDIOBJECTDATAFORMAT podf = &this->df.rgodf[uiObj];
  68. DIOBJECTCALIBRATION cal;
  69. #ifdef WINNT
  70. DIPOVCALIBRATION pov;
  71. #endif
  72. D(LPCTSTR ptszWhence;)
  73. /*
  74. * Note, we do not have to deal with mice on Win2k, yet...
  75. */
  76. #ifdef WINNT
  77. HRESULT hres;
  78. HKEY hk;
  79. D( ptszWhence = TEXT("unknown") );
  80. if( podf->dwType & DIDFT_POV )
  81. {
  82. if( pcaps->IsPolledPOV ) {
  83. ZeroX( pov );
  84. hres = CType_OpenIdSubkey(this->hkInstType, podf->dwType,
  85. KEY_QUERY_VALUE, &hk);
  86. if(SUCCEEDED(hres))
  87. {
  88. hres = JoyReg_GetValue(hk, TEXT("Calibration"),
  89. REG_BINARY, &pov,
  90. cbX(DIPOVCALIBRATION));
  91. RegCloseKey(hk);
  92. }
  93. }
  94. } else
  95. {
  96. ZeroX( cal );
  97. hres = CType_OpenIdSubkey(this->hkInstType, podf->dwType,
  98. KEY_QUERY_VALUE, &hk);
  99. if(SUCCEEDED(hres))
  100. {
  101. hres = JoyReg_GetValue(hk, TEXT("Calibration"),
  102. REG_BINARY, &cal,
  103. cbX(DIOBJECTCALIBRATION));
  104. RegCloseKey(hk);
  105. }
  106. /*
  107. * If there is no calibration data, then create
  108. * some defaults based on the logical min/max.
  109. */
  110. if(FAILED(hres))
  111. {
  112. /*
  113. * But only if the logical min/max is sane!
  114. */
  115. if(pcaps->Logical.Min < pcaps->Logical.Max)
  116. {
  117. cal.lMin = pcaps->Logical.Min;
  118. /*
  119. * HACKHACK
  120. * The analog joystick driver cannot report the true
  121. * range of the device, so to keep the sample driver
  122. * pure, it reports a range of zero to the point at
  123. * which it would consider the axis absent. This is
  124. * good in terms of reporting healthy HID data but
  125. * it means that any normal joystick will only return
  126. * values in a fraction of this range. So if this
  127. * device is an analog device default the calibration
  128. * to the typical range.
  129. */
  130. if( ( this->VendorID == MSFT_SYSTEM_VID )
  131. &&( ( this->ProductID & 0xff00 ) == MSFT_SYSTEM_PID ) )
  132. {
  133. /*
  134. * To be extra safe, compute the max from the
  135. * reported range. The divisor is a fudge factor
  136. * derived by what looked about right to MarcAnd.
  137. */
  138. cal.lMax = pcaps->Logical.Min +
  139. ( ( pcaps->Logical.Max - pcaps->Logical.Min ) / 11 );
  140. D(ptszWhence = TEXT("log (adj)"));
  141. }
  142. else
  143. {
  144. cal.lMax = pcaps->Logical.Max;
  145. D(ptszWhence = TEXT("log"));
  146. }
  147. } else
  148. {
  149. D(ptszWhence = TEXT("def"));
  150. cal.lMin = 0;
  151. cal.lMax = 655;
  152. }
  153. cal.lCenter = CCal_Midpoint(cal.lMin, cal.lMax);
  154. } else
  155. {
  156. D(ptszWhence = TEXT("reg"));
  157. }
  158. }
  159. #else
  160. if( GET_DIDEVICE_TYPE(this->dwDevType) == DI8DEVTYPE_MOUSE )
  161. {
  162. if( this->df.rgodf[uiObj].dwType & DIDFT_ABSAXIS )
  163. {
  164. if(pcaps->Logical.Min < pcaps->Logical.Max)
  165. {
  166. cal.lMin = pcaps->Logical.Min;
  167. cal.lMax = pcaps->Logical.Max;
  168. D(ptszWhence = TEXT("mouse log"));
  169. }
  170. else
  171. {
  172. /*
  173. * Absolute mice traditionally report 0 - 64K
  174. */
  175. cal.lMin = 0;
  176. cal.lMax = 65535;
  177. D(ptszWhence = TEXT("mouse def"));
  178. }
  179. cal.lCenter = CCal_Midpoint(cal.lMin, cal.lMax);
  180. }
  181. else
  182. {
  183. /*
  184. * Relative mouse axis, just zero to keep sane
  185. */
  186. ZeroX( cal );
  187. }
  188. } else if ( this->idJoy < 0 ) //See manbug 50591
  189. {
  190. HRESULT hres;
  191. HKEY hk;
  192. ZeroX( cal );
  193. hres = CType_OpenIdSubkey(this->hkInstType, podf->dwType,
  194. KEY_QUERY_VALUE, &hk);
  195. if(SUCCEEDED(hres))
  196. {
  197. hres = JoyReg_GetValue(hk, TEXT("Calibration"),
  198. REG_BINARY, &cal,
  199. cbX(DIOBJECTCALIBRATION));
  200. RegCloseKey(hk);
  201. } else {
  202. /*
  203. * But only if the logical min/max is sane!
  204. */
  205. if(pcaps->Logical.Min < pcaps->Logical.Max)
  206. {
  207. cal.lMin = pcaps->Logical.Min;
  208. cal.lMax = pcaps->Logical.Max;
  209. } else
  210. {
  211. cal.lMin = 0;
  212. cal.lMax = 655; //best guess
  213. }
  214. cal.lCenter = CCal_Midpoint(cal.lMin, cal.lMax);
  215. }
  216. D(ptszWhence = TEXT("non-gamecontroller"));
  217. } else
  218. {
  219. ZeroX( cal );
  220. /*
  221. * Because the CPL on Win9x only updates calibration in MediaResources,
  222. * We need read that calibration information and update for HID.
  223. */
  224. CHid_UpdateCalibrationFromVjoyd(this, uiObj, &cal);
  225. D(ptszWhence = TEXT("WinMM Reg"));
  226. }
  227. #endif
  228. #ifdef WINNT
  229. if( podf->dwType & DIDFT_POV )
  230. {
  231. if( pcaps->IsPolledPOV ) {
  232. memcpy( pjrc->lMinPOV, pov.lMin, cbX(pjrc->lMinPOV) );
  233. memcpy( pjrc->lMaxPOV, pov.lMax, cbX(pjrc->lMaxPOV) );
  234. }
  235. } else
  236. #endif
  237. {
  238. D(SquirtSqflPtszV(sqflHidParse,
  239. TEXT(" Calibration(%d) %s %d..%d..%d"),
  240. CHid_ObjFromType(this, podf->dwType), ptszWhence,
  241. cal.lMin, cal.lCenter, cal.lMax));
  242. /*
  243. * Saturation always defaults to 100%.
  244. */
  245. pjrc->dwPmin = cal.lMin;
  246. pjrc->dwPmax = cal.lMax;
  247. pjrc->dwPc = cal.lCenter;
  248. if( pjrc->dwCPointsNum == 0 ) {
  249. //use two control points by default
  250. pjrc->dwCPointsNum = 2;
  251. pjrc->cp[0].lP = pjrc->dwPmin;
  252. pjrc->cp[0].dwLog = 0;
  253. pjrc->cp[1].lP = pjrc->dwPmax;
  254. pjrc->cp[1].dwLog = RANGEDIVISIONS;
  255. } else {
  256. pjrc->cp[0].lP = pjrc->dwPmin;
  257. pjrc->cp[pjrc->dwCPointsNum-1].lP = pjrc->dwPmax;
  258. }
  259. CCal_RecalcRange(pjrc);
  260. uiRc++;
  261. }
  262. }
  263. }
  264. return uiRc;
  265. }
  266. /*****************************************************************************
  267. *
  268. * @doc INTERNAL
  269. *
  270. * @func void | CHid_SortCaps |
  271. *
  272. * Sort the capabilities by Data Index. This is important
  273. * so that the items are assigned numbers in the same order
  274. * by both DirectInput and HID.
  275. *
  276. * Note that we exploit the not-exactly-a-coincidence
  277. * that a <t HIDP_VALUE_CAPS> and a
  278. * <t HIDP_BUTTON_CAPS> are identical wherever they overlap.
  279. *
  280. * @parm PV | rgv |
  281. *
  282. * Array of either <t HIDP_VALUE_CAPS> or <t HIDP_BUTTON_CAPS>
  283. * structures.
  284. *
  285. * @parm UINT | cv |
  286. *
  287. * Number of structures that need to be sorted.
  288. *
  289. *****************************************************************************/
  290. void INTERNAL
  291. CHid_SortCaps(PV rgv, UINT cv)
  292. {
  293. /*
  294. * For concreteness, we use HIDP_VALUE_CAPS.
  295. */
  296. PHIDP_VALUE_CAPS rgvcaps = rgv;
  297. UINT ivcaps;
  298. /*
  299. * There are several non-coincidences which we exploit.
  300. *
  301. * HIDP_VALUE_CAPS and HIDP_BUTTON_CAPS are the same size.
  302. *
  303. * HIDP_VALUE_CAPS.Range.DataIndexMin,
  304. * HIDP_VALUE_CAPS.NotRange.DataIndex,
  305. * HIDP_BUTTON_CAPS.Range.DataIndexMin, and
  306. * HIDP_BUTTON_CAPS.NotRange.DataIndex are all at the same offset.
  307. */
  308. CAssertF(cbX(HIDP_VALUE_CAPS) == cbX(HIDP_BUTTON_CAPS));
  309. /*
  310. * For some reason, the compiler doesn't think that these
  311. * expressions are constant so I can't use CAssertF.
  312. */
  313. AssertF(FIELD_OFFSET(HIDP_VALUE_CAPS, NotRange.DataIndex) ==
  314. FIELD_OFFSET(HIDP_VALUE_CAPS, Range.DataIndexMin));
  315. AssertF(FIELD_OFFSET(HIDP_VALUE_CAPS, Range.DataIndexMin) ==
  316. FIELD_OFFSET(HIDP_BUTTON_CAPS, Range.DataIndexMin));
  317. AssertF(FIELD_OFFSET(HIDP_BUTTON_CAPS, Range.DataIndexMin) ==
  318. FIELD_OFFSET(HIDP_BUTTON_CAPS, NotRange.DataIndex));
  319. #ifdef REALLY_ANNOYING
  320. /*
  321. * Dump the Before list.
  322. */
  323. for(ivcaps = 0; ivcaps < cv; ivcaps++)
  324. {
  325. SquirtSqflPtszV(sqflHidParse,
  326. TEXT("HidP_SortCaps:%2d = %04x"),
  327. ivcaps, rgvcaps[ivcaps].Range.DataIndexMin);
  328. }
  329. #endif
  330. /*
  331. * Since there are typically not very many caps, we will use
  332. * a simple insertion sort.
  333. *
  334. * Note if caps entries have the same data index they are
  335. * aliases. Make sure the primary alias will be the first
  336. * in the sorted list.
  337. */
  338. for(ivcaps = 1; ivcaps < cv; ivcaps++)
  339. {
  340. int ivcapsT;
  341. HIDP_VALUE_CAPS vcaps = rgvcaps[ivcaps];
  342. ivcapsT = ivcaps;
  343. while( ( --ivcapsT >= 0 )
  344. &&( ( rgvcaps[ivcapsT].Range.DataIndexMin >
  345. vcaps.Range.DataIndexMin )
  346. ||( ( rgvcaps[ivcapsT].Range.DataIndexMin ==
  347. vcaps.Range.DataIndexMin )
  348. &&( rgvcaps[ivcapsT].IsAlias ) ) ) )
  349. {
  350. rgvcaps[ivcapsT+1] = rgvcaps[ivcapsT];
  351. }
  352. rgvcaps[ivcapsT+1] = vcaps;
  353. }
  354. #ifdef REALLY_ANNOYING
  355. /*
  356. * Dump the After list.
  357. */
  358. for(ivcaps = 0; ivcaps < cv; ivcaps++)
  359. {
  360. SquirtSqflPtszV(sqflHidParse,
  361. TEXT("HidP_SortCaps:%2d = %04x"),
  362. ivcaps, rgvcaps[ivcaps].Range.DataIndexMin);
  363. }
  364. #endif
  365. /*
  366. * Assert that everything is weakly monotonically sorted.
  367. *
  368. * If two items are equal, then it means that HID messed up
  369. * or the values are aliases.
  370. * We don't complain about it here; we will notice later.
  371. */
  372. for(ivcaps = 1; ivcaps < cv; ivcaps++)
  373. {
  374. AssertF(rgvcaps[ivcaps-1].Range.DataIndexMin <=
  375. rgvcaps[ivcaps ].Range.DataIndexMin);
  376. }
  377. }
  378. /*****************************************************************************
  379. *
  380. * @doc INTERNAL
  381. *
  382. * @func DWORD | CHid_FindAspect |
  383. *
  384. * Try to determine the aspect flags for this value.
  385. *
  386. * @parm PHIDP_VALUE_CAPS | pvcaps |
  387. *
  388. * Pointer to HID value caps to search through
  389. * structures.
  390. *
  391. * @returns
  392. *
  393. * Flags set for the aspect if found
  394. *
  395. * @comm
  396. * Currently (08-Dec-98) most devices and drivers do not
  397. * declare units but since drivers must use the generic
  398. * position usages in order to be recognized assume that
  399. * these imply that position data is being returned.
  400. *
  401. *****************************************************************************/
  402. DWORD CHID_FindAspect
  403. (
  404. PHIDP_VALUE_CAPS pvcaps
  405. )
  406. {
  407. DWORD dwAspect = 0;
  408. if( pvcaps->Units )
  409. {
  410. #define HID_UNIT_SYSTEM_MASK 0x0000000fL
  411. #define HID_UNIT_LENGTH_MASK 0x000000f0L
  412. #define HID_UNIT_MASS_MASK 0x00000f00L
  413. #define HID_UNIT_TIME_MASK 0x0000f000L
  414. /*
  415. * If available, use the units to derive the DI aspect
  416. * flags for input objects.
  417. */
  418. if( pvcaps->Units & ~( HID_UNIT_SYSTEM_MASK
  419. | HID_UNIT_LENGTH_MASK
  420. | HID_UNIT_MASS_MASK
  421. | HID_UNIT_TIME_MASK ) )
  422. {
  423. SquirtSqflPtszV(sqflTrace | sqflHidParse,
  424. TEXT("Unit 0x%08x contains basic units that cannot be translated to aspects"),
  425. pvcaps->Units );
  426. }
  427. else
  428. {
  429. /*
  430. * The system of measurement should be one of the
  431. * four defined systems and the length must be one
  432. * dimensional.
  433. */
  434. if( ( ( pvcaps->Units & ( HID_UNIT_SYSTEM_MASK | HID_UNIT_LENGTH_MASK ) ) >= 0x11 )
  435. &&( ( pvcaps->Units & ( HID_UNIT_SYSTEM_MASK | HID_UNIT_LENGTH_MASK ) ) <= 0x14 ) )
  436. {
  437. switch( pvcaps->Units & ( HID_UNIT_TIME_MASK | HID_UNIT_MASS_MASK ) )
  438. {
  439. case 0x0000:
  440. dwAspect = DIDOI_ASPECTPOSITION;
  441. break;
  442. case 0xf000:
  443. dwAspect = DIDOI_ASPECTVELOCITY;
  444. break;
  445. case 0xe000:
  446. dwAspect = DIDOI_ASPECTACCEL;
  447. break;
  448. case 0xe100:
  449. dwAspect = DIDOI_ASPECTFORCE;
  450. break;
  451. default:
  452. if( 0x0004 == ( pvcaps->Units & ( HID_UNIT_TIME_MASK | HID_UNIT_MASS_MASK | HID_UNIT_SYSTEM_MASK ) ) )
  453. {
  454. SquirtSqflPtszV(sqflTrace | sqflHidParse,
  455. TEXT("Unit \"degrees\" will not be mapped to a DI aspect (probably a POV)") );
  456. }
  457. else
  458. {
  459. SquirtSqflPtszV(sqflTrace | sqflHidParse,
  460. TEXT("Unit 0x%04x represents a mass/time unit that cannot be translated to aspects"),
  461. pvcaps->Units );
  462. }
  463. }
  464. }
  465. else
  466. {
  467. SquirtSqflPtszV(sqflTrace | sqflHidParse,
  468. TEXT("Unit 0x%04x contains represents a length/system unit that cannot be translated to aspects"),
  469. pvcaps->Units );
  470. }
  471. }
  472. #ifdef DEBUG
  473. if( dwAspect )
  474. {
  475. SquirtSqflPtszV(sqflVerbose | sqflHidParse,
  476. TEXT("Unit 0x%04x translated to aspect 0x%04x"),
  477. pvcaps->Units, dwAspect );
  478. }
  479. #endif
  480. #undef HID_UNIT_SYSTEM_MASK
  481. #undef HID_UNIT_LENGTH_MASK
  482. #undef HID_UNIT_MASS_MASK
  483. #undef HID_UNIT_TIME_MASK
  484. }
  485. else
  486. {
  487. PHIDUSAGEMAP phum;
  488. phum = UsageToUsageMap( DIMAKEUSAGEDWORD( pvcaps->UsagePage,
  489. pvcaps->Range.UsageMin ) );
  490. if( phum && phum->bPosAxis <= 6 )
  491. {
  492. phum = UsageToUsageMap( DIMAKEUSAGEDWORD( pvcaps->UsagePage,
  493. pvcaps->Range.UsageMax ) );
  494. if( phum && phum->bPosAxis <= 6 )
  495. {
  496. dwAspect = DIDOI_ASPECTPOSITION;
  497. }
  498. }
  499. else
  500. {
  501. SquirtSqflPtszV(sqflTrace | sqflHidParse,
  502. TEXT("No aspect found for 0x%04x page usage 0x%04x-0x%04x"),
  503. pvcaps->UsagePage, pvcaps->Range.UsageMin, pvcaps->Range.UsageMax );
  504. }
  505. #ifdef DEBUG
  506. if( dwAspect )
  507. {
  508. SquirtSqflPtszV(sqflVerbose | sqflHidParse,
  509. TEXT("Usage (page:min-max) 0x%04x:0x%04x-0x%04x translated to aspect 0x%04x"),
  510. pvcaps->UsagePage, pvcaps->Range.UsageMin, pvcaps->Range.UsageMax, dwAspect );
  511. }
  512. #endif
  513. }
  514. return dwAspect;
  515. }
  516. /*****************************************************************************
  517. *
  518. * @doc INTERNAL
  519. *
  520. * @method HRESULT | CHid | InitAxisClass |
  521. *
  522. * Initialize one class (input, feature, output) of axes.
  523. *
  524. * @parm PHIDGROUPCAPS | rgcaps |
  525. *
  526. * Array of <t HIDGROUPCAPS> structures to receive the caps
  527. * of the axes in the class.
  528. *
  529. * @parm USHORT | ccaps |
  530. *
  531. * Number of <t HIDGROUPCAPS> structures we expect to find.
  532. *
  533. * @parm HIDP_REPORT_TYPE | type |
  534. *
  535. * One of the values
  536. * <c HidP_Input>,
  537. * <c HidP_Feature> or
  538. * <c HidP_Output>.
  539. *
  540. *****************************************************************************/
  541. HRESULT INTERNAL
  542. CHid_InitAxisClass(PCHID this, PHIDGROUPCAPS rgcaps, USHORT ccaps,
  543. HIDP_REPORT_TYPE type)
  544. {
  545. USHORT cvcaps;
  546. NTSTATUS stat;
  547. HRESULT hres;
  548. DWORD ivcaps;
  549. LONG lSignedMask;
  550. PHIDP_VALUE_CAPS rgvcaps;
  551. AssertF(rgcaps >= this->rgcaps);
  552. AssertF(rgcaps + ccaps <= &this->rgcaps[this->ccaps]);
  553. /*
  554. * Annoying quirk:
  555. *
  556. * HID doesn't like it when you pass 0 to HidP_GetValueCaps,
  557. * so we need to special-case the "no axes" scenario.
  558. */
  559. if(ccaps == 0)
  560. {
  561. hres = S_OK;
  562. goto done;
  563. }
  564. hres = AllocCbPpv(cbCxX(ccaps, HIDP_VALUE_CAPS), &rgvcaps);
  565. if(FAILED(hres))
  566. {
  567. goto done;
  568. }
  569. cvcaps = ccaps;
  570. stat = HidP_GetValueCaps(type, rgvcaps, &cvcaps, this->ppd);
  571. if(FAILED(stat))
  572. {
  573. RPF("HidP_GetValueCaps failed - can't use device");
  574. hres = E_FAIL;
  575. goto freedone;
  576. }
  577. if(cvcaps != ccaps)
  578. {
  579. RPF("HidP_GetValueCaps inconsistent with HidP_GetCaps - "
  580. "can't use device");
  581. hres = E_FAIL;
  582. goto freedone;
  583. }
  584. CHid_SortCaps(rgvcaps, cvcaps);
  585. for(ivcaps = 0; ivcaps < cvcaps; ivcaps++)
  586. {
  587. PHIDP_VALUE_CAPS pvcaps = &rgvcaps[ivcaps];
  588. PHIDGROUPCAPS pcaps = &rgcaps[ivcaps];
  589. BOOL fPOV;
  590. UINT uiObj;
  591. UINT duiObj;
  592. DWORD dwAspect;
  593. /*
  594. * ISSUE-2001/03/06-MarcAnd Ignoring report count
  595. * We ignore the report count which may be bad, need
  596. * to test device with values declared in a range to see what HID
  597. * really gives us.
  598. * At the descriptor level, values can be delared in a range with
  599. * usages and the last usage is repeated for any excess values.
  600. */
  601. if(pvcaps->IsRange)
  602. {
  603. if(pvcaps->Range.DataIndexMax - pvcaps->Range.DataIndexMin !=
  604. pvcaps->Range.UsageMax - pvcaps->Range.UsageMin)
  605. {
  606. RPF("HidP_GetValueCaps corrupted VALUE_CAPS - "
  607. "can't use device");
  608. hres = E_FAIL;
  609. goto freedone;
  610. }
  611. } else
  612. {
  613. pvcaps->Range.UsageMax = pvcaps->Range.UsageMin;
  614. }
  615. if( ( type == HidP_Input ) && !pvcaps->IsAlias )
  616. {
  617. /*
  618. * The values are sorted by data index with the primary alias
  619. * before any other. So find out the aspect of the axis each
  620. * time we get a new primary and use it for any alias that follow.
  621. */
  622. dwAspect = CHID_FindAspect( pvcaps );
  623. }
  624. pcaps->wReportId = pvcaps->ReportID;
  625. this->wMaxReportId[type] = max(pcaps->wReportId, this->wMaxReportId[type]);
  626. pcaps->UsagePage = pvcaps->UsagePage;
  627. pcaps->UsageMin = pvcaps->Range.UsageMin;
  628. pcaps->DataIndexMin = pvcaps->Range.DataIndexMin;
  629. pcaps->cObj = pvcaps->Range.UsageMax -
  630. pvcaps->Range.UsageMin + 1;
  631. /*
  632. * The mask consists of the top bit of the BitSize and
  633. * all bits above it. Examples:
  634. *
  635. * BitSize 8 32
  636. * BitSize - 1 7 31
  637. * 1 << (BitSize - 1) 0x00000080 0x80000000
  638. * (1 << (BitSize - 1)) - 1 0x0000007F 0x7FFFFFFF
  639. * ~((1 << (BitSize - 1)) - 1) 0xFFFFFF80 0x80000000
  640. *
  641. */
  642. pcaps->BitSize = pvcaps->BitSize;
  643. pcaps->lMask = ~((1 << (pcaps->BitSize - 1)) - 1);
  644. lSignedMask = max( 1, ( 1 << pcaps->BitSize) -1 );
  645. pcaps->LinkCollection = pvcaps->LinkCollection;
  646. pcaps->Units = pvcaps->Units;
  647. pcaps->Exponent = LOWORD(pvcaps->UnitsExp);
  648. pcaps->Logical.Min = pvcaps->LogicalMin;
  649. pcaps->Logical.Max = pvcaps->LogicalMax;
  650. pcaps->Physical.Min = pvcaps->PhysicalMin;
  651. pcaps->Physical.Max = pvcaps->PhysicalMax;
  652. if(pcaps->Logical.Min >= pcaps->Logical.Max)
  653. {
  654. RPF("HidP_GetValueCaps Logical Min >= Logical Max - ");
  655. if( pcaps->Physical.Min < pcaps->Physical.Max )
  656. {
  657. pcaps->Logical = pcaps->Physical;
  658. } else
  659. {
  660. pcaps->Logical.Min = pcaps->lMask;
  661. pcaps->Logical.Max = ~pcaps->lMask;
  662. }
  663. SquirtSqflPtszV(sqflHidParse | sqflVerbose,
  664. TEXT("HidP_GetValueCaps:")
  665. TEXT("Logical Min(was:%d now:%d)")
  666. TEXT("Logical Max(was:%d now:%d)"),
  667. pvcaps->LogicalMin, pcaps->Logical.Min,
  668. pvcaps->LogicalMax, pcaps->Logical.Max);
  669. }
  670. /*
  671. * the range for LogicalMin / LogicalMax had better fall
  672. * within the range of values the device can possibly
  673. * report.
  674. *
  675. * The lMask value happens also to be the smallest possible
  676. * negative value, and the bitwise negation of it happens
  677. * to be the largest possible positive value. The wonders
  678. * of two-s complement arithmetic.
  679. */
  680. /*
  681. * Extra case is fix for 268519
  682. */
  683. if(pcaps->Physical.Min > pcaps->Physical.Max)
  684. {
  685. RPF("HidP_GetValueCaps Physical Min/Max(%d/%d) is bad setting all to zero to %d"
  686. "device may have bad firmware", pcaps->Physical.Min, pcaps->Physical.Max, lSignedMask);
  687. pcaps->Logical.Min = 0;
  688. pcaps->Physical.Min = 0;
  689. pcaps->Logical.Max = lSignedMask;
  690. pcaps->Physical.Max = lSignedMask;
  691. pcaps->lMask = lSignedMask;
  692. pcaps->IsSigned = FALSE;
  693. }
  694. else
  695. {
  696. if(pcaps->Physical.Min == pcaps->Physical.Max)
  697. {
  698. pcaps->Physical = pcaps->Logical;
  699. }
  700. if(pcaps->Logical.Min >= pcaps->lMask && // Logical Min / Max are signed
  701. pcaps->Logical.Max <= ~pcaps->lMask)
  702. {
  703. pcaps->IsSigned = TRUE;
  704. } else if(pcaps->Logical.Min >= 0 &&
  705. pcaps->Logical.Max <= lSignedMask )
  706. { // Logical Min / Max are unsigned
  707. pcaps->lMask = lSignedMask;
  708. pcaps->IsSigned = FALSE;
  709. } else if (pcaps->UsagePage >= HID_USAGE_PAGE_VENDOR )
  710. {
  711. // Let this one pass, hopefully the broken descriptors are for
  712. // usages that are vendor specific and will not effect too many folks
  713. RPF("HidP_GetValueCaps Logical Min/Max(%d/%d) don't fit in BitSize(%d) - "
  714. "device may have bad firmware", pcaps->Logical.Min, pcaps->Logical.Max, pcaps->BitSize);
  715. pcaps->Logical.Min = pcaps->lMask;
  716. pcaps->Logical.Max = ~pcaps->lMask;
  717. pcaps->IsSigned = TRUE;
  718. }else
  719. {
  720. RPF("HidP_GetValueCaps UsagePage(0x%x)Usage(0x%x) Logical Min/Max(%d/%d) don't fit in BitSize(%d) - "
  721. "can't use device", pcaps->UsagePage, pcaps->UsageMin, pcaps->Logical.Min, pcaps->Logical.Max, pcaps->BitSize);
  722. hres = E_FAIL;
  723. goto freedone;
  724. }
  725. }
  726. AssertF(pcaps->Physical.Min < pcaps->Physical.Max);
  727. pcaps->StringMin = pvcaps->Range.StringMin;
  728. pcaps->StringMax = pvcaps->IsStringRange ?
  729. pvcaps->Range.StringMax :
  730. pvcaps->Range.StringMin;
  731. pcaps->DesignatorMin = pvcaps->Range.DesignatorMin;
  732. pcaps->DesignatorMax = pvcaps->IsDesignatorRange ?
  733. pvcaps->Range.DesignatorMax :
  734. pvcaps->Range.DesignatorMin;
  735. pcaps->IsAbsolute = pvcaps->IsAbsolute;
  736. pcaps->IsValue = TRUE;
  737. pcaps->IsAlias = pvcaps->IsAlias;
  738. pcaps->type = type;
  739. /*
  740. * HID reports axes and POVs as the same thing, and the two
  741. * POV usages we recognize are in different pages, so you
  742. * will never get multiple POVs coming through in a single
  743. * value-caps.
  744. *
  745. * ISSUE-2001/03/06-MarcAnd POVs within caps are treated as axes
  746. * There is, however, the problem of a POV buried inside
  747. * a larger value-cap that describes axes. Tough. Those
  748. * POVs are in trouble.
  749. */
  750. #define HID_USAGE_GAME_POV ((USAGE) 0x20)
  751. fPOV = pcaps->cObj == 1
  752. && ( ( pcaps->UsagePage == HID_USAGE_PAGE_GENERIC
  753. &&pcaps->UsageMin == HID_USAGE_GENERIC_HATSWITCH )
  754. ||( pcaps->UsagePage == HID_USAGE_PAGE_GAME
  755. &&pcaps->UsageMin == HID_USAGE_GAME_POV ) );
  756. if(fPOV)
  757. {
  758. LONG lUnits;
  759. /*
  760. * POVs are assumed to start at north and increase
  761. * clockwise through the logical maximum.
  762. */
  763. lUnits = pcaps->Logical.Max - pcaps->Logical.Min + 1;
  764. if(lUnits)
  765. {
  766. pcaps->usGranularity = (USHORT)(36000U / lUnits);
  767. }
  768. } else
  769. {
  770. if( ( pcaps->UsagePage == HID_USAGE_PAGE_GENERIC &&
  771. pcaps->UsageMin <= HID_USAGE_GENERIC_HATSWITCH &&
  772. pvcaps->Range.UsageMax >= HID_USAGE_GENERIC_HATSWITCH )
  773. ||( pcaps->UsagePage == HID_USAGE_PAGE_GAME &&
  774. pcaps->UsageMin <= HID_USAGE_GAME_POV &&
  775. pvcaps->Range.UsageMax >= HID_USAGE_GAME_POV ) )
  776. {
  777. SquirtSqflPtszV(sqflHidParse | sqflError,
  778. TEXT("HidP_GetValueCaps - multi-usage cap ")
  779. TEXT("includes hatswitch or POV - will be treated")
  780. TEXT("as axis"));
  781. }
  782. }
  783. #undef HID_USAGE_GAME_POV
  784. SquirtSqflPtszV(sqflVerbose | sqflHidParse,
  785. TEXT("HidP_GetValueCaps(%d)[%d]: Objs = %d"),
  786. type, ivcaps, pcaps->cObj);
  787. SquirtSqflPtszV(sqflVerbose | sqflHidParse,
  788. TEXT("HidP_GetValueCaps(%d)[%d]: Index %d ..."),
  789. type, ivcaps,
  790. pcaps->DataIndexMin);
  791. SquirtSqflPtszV(sqflVerbose | sqflHidParse,
  792. TEXT("HidP_GetValueCaps(%d)[%d]: Logical = %d..%d"),
  793. type, ivcaps,
  794. pcaps->Logical.Min, pcaps->Logical.Max);
  795. SquirtSqflPtszV(sqflVerbose | sqflHidParse,
  796. TEXT("HidP_GetValueCaps(%d)[%d]: Physical = %d..%d"),
  797. type, ivcaps,
  798. pcaps->Physical.Min, pcaps->Physical.Max);
  799. SquirtSqflPtszV(sqflVerbose | sqflHidParse,
  800. TEXT("HidP_GetValueCaps(%d)[%d]: Units = 0x%08x"),
  801. type, ivcaps,
  802. pcaps->Units);
  803. SquirtSqflPtszV(sqflVerbose | sqflHidParse,
  804. TEXT("HidP_GetValueCaps(%d)[%d]: IsAbs = %d"),
  805. type, ivcaps,
  806. pcaps->IsAbsolute);
  807. SquirtSqflPtszV(sqflVerbose | sqflHidParse,
  808. TEXT("HidP_GetValueCaps(%d)[%d]: BitSize = %d"),
  809. type, ivcaps,
  810. pcaps->BitSize);
  811. SquirtSqflPtszV(sqflVerbose | sqflHidParse,
  812. TEXT("HidP_GetValueCaps(%d)[%d]: IsAlias = %d"),
  813. type, ivcaps,
  814. pcaps->IsAlias);
  815. if(pcaps->LinkCollection)
  816. {
  817. SquirtSqflPtszV(sqflVerbose | sqflHidParse,
  818. TEXT("HidP_GetValueCaps(%d)[%d]: ")
  819. TEXT("LinkCollection %d"),
  820. type, ivcaps,
  821. pcaps->LinkCollection);
  822. }
  823. /*
  824. * Come up with a decent Null value if possible.
  825. * The traditional Null value is the arithmetically
  826. * smallest value which lies outside the
  827. * LogicalMin/LogicalMax range. Conveniently, the
  828. * pcaps->lMask is the most negative value that is
  829. * in range.
  830. */
  831. AssertF(pcaps->Null == 0);
  832. if(pvcaps->HasNull)
  833. {
  834. #ifdef WINNT
  835. pcaps->IsPolledPOV = FALSE;
  836. #endif
  837. if(pcaps->lMask < pcaps->Logical.Min)
  838. {
  839. pcaps->Null = pcaps->lMask;
  840. } else if(!(pcaps->lMask & (pcaps->Logical.Max + 1)))
  841. {
  842. pcaps->Null = pcaps->Logical.Max + 1;
  843. } else if( ! pcaps->IsSigned )
  844. {
  845. pcaps->Null = 0x0;
  846. } else
  847. {
  848. SquirtSqflPtszV(sqflTrace,
  849. TEXT("VALUE_CAPS claims Null but no room!"));
  850. }
  851. SquirtSqflPtszV(sqflVerbose | sqflHidParse,
  852. TEXT("HidP_GetValueCaps(%d)[%d]: Null = %d"),
  853. type, ivcaps,
  854. pcaps->Null);
  855. } else {
  856. #ifdef WINNT
  857. if( fPOV &&
  858. (this->VendorID == MSFT_SYSTEM_VID ) &&
  859. ( (this->ProductID & 0xff00) == MSFT_SYSTEM_PID) )
  860. {
  861. LONG lUnits;
  862. lUnits = pcaps->Logical.Max - pcaps->Logical.Min + 1;
  863. if(lUnits)
  864. {
  865. pcaps->usGranularity = (USHORT)9000;
  866. }
  867. pcaps->IsPolledPOV = TRUE;
  868. SquirtSqflPtszV(sqflVerbose | sqflHidParse,
  869. TEXT("HidP_GetValueCaps(%d)[%d]: Null = %d (Polled POV)."),
  870. type, ivcaps,
  871. pcaps->Null);
  872. }
  873. #endif
  874. }
  875. uiObj = this->rgdwBase[type] + pcaps->DataIndexMin;
  876. for(duiObj = 0; duiObj < pcaps->cObj; duiObj++)
  877. {
  878. DWORD dwObjType;
  879. LPDIOBJECTDATAFORMAT podf;
  880. /*
  881. * If HID messed up and gave us something out of range,
  882. * then give up on this value caps (since the rest are
  883. * also out of range) and move on to the next one.
  884. */
  885. if(uiObj + duiObj >= this->df.dwNumObjs)
  886. {
  887. RPF("HidP_GetValueCaps inconsistent with NumberDataIndices - "
  888. "skipping object (sorry)");
  889. break;
  890. }
  891. AssertF(uiObj + duiObj < this->df.dwNumObjs);
  892. if(this->rghoc[uiObj + duiObj].pcaps)
  893. {
  894. RPF("HidP_GetValueCaps inconsistent - "
  895. "can't use device");
  896. hres = E_FAIL;
  897. goto freedone;
  898. }
  899. this->rghoc[uiObj + duiObj].pcaps = pcaps;
  900. podf = &this->df.rgodf[uiObj + duiObj];
  901. /*
  902. * HACKHACK! Wheels are identified by
  903. * UsageToUsageMap as GUID_Slider, but we
  904. * want them to be GUID_ZAxis if we are a mouse.
  905. *
  906. * We also set the granularity here.
  907. */
  908. if(GET_DIDEVICE_TYPE(this->dwDevType) == DI8DEVTYPE_MOUSE &&
  909. pcaps->UsageMin + duiObj == HID_USAGE_GENERIC_WHEEL &&
  910. pcaps->UsagePage == HID_USAGE_PAGE_GENERIC)
  911. {
  912. podf->pguid = &GUID_ZAxis;
  913. pcaps->usGranularity = (USHORT)g_lWheelGranularity;
  914. } else if( type == HidP_Input )
  915. {
  916. PHIDUSAGEMAP phum;
  917. phum = UsageToUsageMap( DIMAKEUSAGEDWORD( pcaps->UsagePage,
  918. pcaps->UsageMin + duiObj ) );
  919. if(phum)
  920. {
  921. podf->pguid = phum->pguid;
  922. } else
  923. {
  924. podf->pguid = &GUID_Unknown;
  925. }
  926. } else
  927. {
  928. podf->pguid = &GUID_Unknown;
  929. }
  930. /*
  931. * Set a default instance. This will be overwritten later
  932. * if this object is of a type we fully understand.
  933. */
  934. dwObjType = DIDFT_MAKEINSTANCE(uiObj + duiObj);
  935. if( pcaps->IsAlias )
  936. {
  937. dwObjType |= DIDFT_ALIAS;
  938. }
  939. if(pcaps->UsagePage >= HID_USAGE_PAGE_VENDOR )
  940. {
  941. dwObjType |= DIDFT_VENDORDEFINED;
  942. }
  943. else if(podf->pguid == &GUID_POV)
  944. {
  945. /* Note, this must be an input to have been mapped */
  946. dwObjType |= DIDFT_POV;
  947. if( !pcaps->IsAlias )
  948. {
  949. this->dwPOVs++;
  950. }
  951. }
  952. else if( type == HidP_Input )
  953. {
  954. /*
  955. * In order to reduce the likelyhood of an app picking up an
  956. * input value that is not a user controlled axis, only mark
  957. * values as axes if they are inputs on a usage page that
  958. * contains such usages.
  959. * ISSUE-2000/11/07-MarcAnd ideally we should be looking at
  960. * not only the usage of the object but at the collections
  961. * that contain it.
  962. */
  963. switch( pcaps->UsagePage )
  964. {
  965. case HID_USAGE_PAGE_BUTTON:
  966. /*
  967. * The plan was that an absolute input axis on the button
  968. * page would be an analog button. Unfortunately it
  969. * could be a mis-declared button array selector (482186).
  970. * Safest thing is to ignore the thing completely.
  971. */
  972. SquirtSqflPtszV(sqfl | sqflVerbose,
  973. TEXT("Ignoring value on button page usage ID 0x%04X"),
  974. pcaps->UsageMin + duiObj );
  975. break;
  976. case HID_USAGE_PAGE_GENERIC:
  977. if( pcaps->UsageMin + duiObj == HID_USAGE_GENERIC_COUNTED_BUFFER )
  978. {
  979. SquirtSqflPtszV(sqfl | sqflTrace,
  980. TEXT("Leaving counted buffer as unclassified object") );
  981. break;
  982. }
  983. if( pcaps->UsageMin + duiObj == HID_USAGE_GENERIC_BYTE_COUNT )
  984. {
  985. SquirtSqflPtszV(sqfl | sqflTrace,
  986. TEXT("Leaving byte count as unclassified object") );
  987. break;
  988. }
  989. case HID_USAGE_PAGE_SIMULATION:
  990. case HID_USAGE_PAGE_VR:
  991. case HID_USAGE_PAGE_SPORT:
  992. case HID_USAGE_PAGE_GAME:
  993. case HID_USAGE_PAGE_KEYBOARD:
  994. case HID_USAGE_PAGE_CONSUMER:
  995. case HID_USAGE_PAGE_DIGITIZER:
  996. if( pcaps->IsAbsolute)
  997. {
  998. dwObjType |= DIDFT_ABSAXIS;
  999. }
  1000. else
  1001. {
  1002. dwObjType |= DIDFT_RELAXIS;
  1003. }
  1004. break;
  1005. default:
  1006. SquirtSqflPtszV(sqfl | sqflTrace,
  1007. TEXT("Assuming value 0x%04X:0x%04X is not a user control"),
  1008. pcaps->UsagePage,pcaps->UsageMin + duiObj );
  1009. }
  1010. if( ( dwObjType & DIDFT_AXIS ) && !pcaps->IsAlias )
  1011. {
  1012. this->dwAxes++;
  1013. }
  1014. }
  1015. /*
  1016. * Objects must have an offset to be accessed
  1017. */
  1018. podf->dwOfs = this->df.dwDataSize;
  1019. if( !pcaps->IsAlias)
  1020. {
  1021. this->df.dwDataSize += cbX(DWORD);
  1022. }
  1023. if(HidP_IsOutputLike(type))
  1024. {
  1025. /*
  1026. * Input and feature allow data; output does not.
  1027. */
  1028. if(type == HidP_Output)
  1029. {
  1030. dwObjType |= ( DIDFT_NODATA | DIDFT_OUTPUT );
  1031. }
  1032. else
  1033. {
  1034. dwObjType |= DIDFT_OUTPUT;
  1035. }
  1036. }
  1037. podf->dwType = dwObjType;
  1038. if(type != HidP_Input )
  1039. {
  1040. podf->dwFlags = DIDOI_POLLED | DIDOI_NOTINPUT;
  1041. }
  1042. else if(this->IsPolledInput )
  1043. {
  1044. podf->dwFlags = dwAspect | DIDOI_POLLED;
  1045. } else
  1046. {
  1047. podf->dwFlags = dwAspect;
  1048. }
  1049. /*
  1050. * ISSUE-2001/03/06-MarcAnd DIDOI FF attributes
  1051. */
  1052. if( this->fPIDdevice // FF device
  1053. && ! IsEqualGUID(podf->pguid, &GUID_Unknown ) ) // We map the axis
  1054. {
  1055. NTSTATUS ntStat;
  1056. USHORT cAButton=0x0;
  1057. ntStat = HidP_GetSpecificButtonCaps
  1058. (
  1059. HidP_Output, // ReportType
  1060. pcaps->UsagePage, // UsagePage
  1061. 0x0, // Link Collection
  1062. (USAGE)(pcaps->UsageMin + duiObj), // Usage
  1063. NULL, // ValueCaps
  1064. &cAButton, // ValueCapsLength
  1065. this->ppd // PreparsedData
  1066. );
  1067. if( SUCCEEDED(ntStat)
  1068. || (ntStat == HIDP_STATUS_BUFFER_TOO_SMALL) )// In case someone has more than one
  1069. {
  1070. podf->dwFlags |= DIDOI_FFACTUATOR;
  1071. podf->dwType |= DIDFT_MAKEATTR(DIDOI_FFACTUATOR);
  1072. }
  1073. }
  1074. /*
  1075. * Note that we do not calibrate relative axes,
  1076. * since there's really nothing to calibrate.
  1077. *
  1078. * Note also that we calibrate only inputs.
  1079. * We don't want to do de-calibration on outputs.
  1080. * (And since features are input+output, we don't
  1081. * do it on features either.)
  1082. *
  1083. * We merely set up the calibration here; the
  1084. * reading of the calibration values is done
  1085. * by CHid_LoadCalibrations.
  1086. *
  1087. */
  1088. if(type == HidP_Input)
  1089. {
  1090. PJOYRANGECONVERT pjrc = this->pjrcNext++;
  1091. this->rghoc[uiObj + duiObj].pjrc = pjrc;
  1092. /*
  1093. * Saturation always defaults to 100%.
  1094. */
  1095. pjrc->dwSat = RANGEDIVISIONS;
  1096. AssertF(pjrc->dwDz == 0);
  1097. if( dwObjType & DIDFT_ABSAXIS )
  1098. {
  1099. pjrc->lMin = 0;
  1100. pjrc->lMax = 65535;
  1101. pjrc->lC = 65535/2;
  1102. }
  1103. #ifdef WINNT
  1104. else if( (dwObjType & DIDFT_POV) && pcaps->IsPolledPOV )
  1105. {
  1106. pjrc->fPolledPOV = TRUE;
  1107. }
  1108. #endif
  1109. }
  1110. }
  1111. D(pcaps->dwSignature = HIDGROUPCAPS_SIGNATURE);
  1112. }
  1113. hres = S_OK;
  1114. freedone:;
  1115. FreePv(rgvcaps);
  1116. done:;
  1117. return hres;
  1118. }
  1119. /*****************************************************************************
  1120. *
  1121. * @doc INTERNAL
  1122. *
  1123. * @method HRESULT | CHid | InitAxes |
  1124. *
  1125. * Identify and initialize the axes: input, feature and output.
  1126. *
  1127. * HID calls them "values" because they might not really
  1128. * be axes in the joystick sense.
  1129. *
  1130. * The input axes come first, then the feature axes,
  1131. * then the output axes.
  1132. *
  1133. *****************************************************************************/
  1134. HRESULT INTERNAL
  1135. CHid_InitAxes(PCHID this)
  1136. {
  1137. HRESULT hres;
  1138. DWORD ccaps;
  1139. /*
  1140. * Do the input axes...
  1141. */
  1142. hres = CHid_InitAxisClass(this, &this->rgcaps[0],
  1143. this->caps.NumberInputValueCaps,
  1144. HidP_Input);
  1145. if(FAILED(hres))
  1146. {
  1147. goto done;
  1148. }
  1149. ccaps = this->caps.NumberInputValueCaps;
  1150. /*
  1151. * Do the feature axes...
  1152. */
  1153. hres = CHid_InitAxisClass(this, &this->rgcaps[ccaps],
  1154. this->caps.NumberFeatureValueCaps,
  1155. HidP_Feature);
  1156. if(FAILED(hres))
  1157. {
  1158. goto done;
  1159. }
  1160. ccaps += this->caps.NumberFeatureValueCaps;
  1161. /*
  1162. * Do the output axes...
  1163. */
  1164. hres = CHid_InitAxisClass(this, &this->rgcaps[ccaps],
  1165. this->caps.NumberOutputValueCaps,
  1166. HidP_Output);
  1167. if(FAILED(hres))
  1168. {
  1169. goto done;
  1170. }
  1171. done:;
  1172. return hres;
  1173. }
  1174. /*****************************************************************************
  1175. *
  1176. * @doc INTERNAL
  1177. *
  1178. * @method HRESULT | CHid | InitButtonClass |
  1179. *
  1180. * Initialize one class (input, feature, output) of buttons.
  1181. *
  1182. * @parm PHIDGROUPCAPS | rgcaps |
  1183. *
  1184. * Array of <t HIDGROUPCAPS> structures to receive the caps
  1185. * of the buttons in the class.
  1186. *
  1187. * @parm USHORT | ccaps |
  1188. *
  1189. * Number of <t HIDGROUPCAPS> structures we expect to find.
  1190. *
  1191. * @parm HIDP_REPORT_TYPE | type |
  1192. *
  1193. * One of the values
  1194. * <c HidP_Input>,
  1195. * <c HidP_Feature> or
  1196. * <c HidP_Output>.
  1197. *
  1198. *****************************************************************************/
  1199. HRESULT INTERNAL CHid_InitButtonClass
  1200. (
  1201. PCHID this,
  1202. PHIDGROUPCAPS rgcaps,
  1203. PBYTE rgbReportIDs,
  1204. USHORT ccaps,
  1205. HIDP_REPORT_TYPE type
  1206. )
  1207. {
  1208. USHORT cbcaps;
  1209. NTSTATUS stat;
  1210. HRESULT hres;
  1211. DWORD ibcaps;
  1212. PHIDP_BUTTON_CAPS rgbcaps;
  1213. AssertF(rgcaps >= this->rgcaps);
  1214. AssertF(rgcaps + ccaps <= &this->rgcaps[this->ccaps]);
  1215. /*
  1216. * Annoying quirk:
  1217. *
  1218. * HID doesn't like it when you pass 0 to HidP_GetButtonCaps,
  1219. * so we need to special-case the "no buttons" scenario.
  1220. */
  1221. if(ccaps == 0)
  1222. {
  1223. hres = S_OK;
  1224. goto done;
  1225. }
  1226. hres = AllocCbPpv(cbCxX(ccaps, HIDP_BUTTON_CAPS), &rgbcaps);
  1227. if(FAILED(hres))
  1228. {
  1229. goto done;
  1230. }
  1231. cbcaps = ccaps;
  1232. stat = HidP_GetButtonCaps(type, rgbcaps, &cbcaps, this->ppd);
  1233. if(FAILED(stat))
  1234. {
  1235. RPF("HidP_GetButtonCaps failed - can't use device");
  1236. hres = E_FAIL;
  1237. goto freedone;
  1238. }
  1239. /* HidP_GetCaps has the annoying habit of treating everything that is
  1240. * single bit as a button.
  1241. * This causes some problems. For example the ALPS gamepad declares its
  1242. * POVs as single bit values, (not buttons though).
  1243. * Hence we need to be prepared for the buttons being less than advertised
  1244. */
  1245. if(cbcaps != ccaps)
  1246. {
  1247. RPF("HidP_GetButtonCaps(%d) (%d) inconsistent "
  1248. "with HidP_GetCaps (%d) - "
  1249. "can't use device", type, cbcaps, ccaps);
  1250. hres = E_FAIL;
  1251. goto freedone;
  1252. }
  1253. CHid_SortCaps(rgbcaps, cbcaps);
  1254. for(ibcaps = 0; ibcaps < cbcaps; ibcaps++)
  1255. {
  1256. PHIDP_BUTTON_CAPS pbcaps = &rgbcaps[ibcaps];
  1257. PHIDGROUPCAPS pcaps = &rgcaps[ibcaps];
  1258. UINT uiObj;
  1259. UINT duiObj;
  1260. if(pbcaps->IsRange)
  1261. {
  1262. if(pbcaps->Range.DataIndexMax - pbcaps->Range.DataIndexMin !=
  1263. pbcaps->Range.UsageMax - pbcaps->Range.UsageMin)
  1264. {
  1265. RPF("HidP_GetButtonCaps corrupted BUTTON_CAPS - "
  1266. "can't use device");
  1267. hres = E_FAIL;
  1268. goto freedone;
  1269. }
  1270. } else
  1271. {
  1272. pbcaps->Range.UsageMax = pbcaps->Range.UsageMin;
  1273. }
  1274. pcaps->wReportId = pbcaps->ReportID;
  1275. this->wMaxReportId[type] = max(pcaps->wReportId, this->wMaxReportId[type]);
  1276. pcaps->UsagePage = pbcaps->UsagePage;
  1277. pcaps->UsageMin = pbcaps->Range.UsageMin;
  1278. pcaps->DataIndexMin = pbcaps->Range.DataIndexMin;
  1279. pcaps->cObj = pbcaps->Range.UsageMax -
  1280. pbcaps->Range.UsageMin + 1;
  1281. /*
  1282. * Buttons are (from the HID definition) items with
  1283. * a bit size of 1.
  1284. */
  1285. pcaps->BitSize = 1;
  1286. pcaps->lMask = ~((1 << (pcaps->BitSize - 1)) - 1);
  1287. /*
  1288. * Not applicable for buttons:
  1289. *
  1290. * LogicalMin/Max, PhysicalMin/Max, Units.
  1291. */
  1292. pcaps->LinkCollection = pbcaps->LinkCollection;
  1293. pcaps->StringMin = pbcaps->Range.StringMin;
  1294. pcaps->StringMax = pbcaps->IsStringRange ?
  1295. pbcaps->Range.StringMax :
  1296. pbcaps->Range.StringMin;
  1297. pcaps->DesignatorMin = pbcaps->Range.DesignatorMin;
  1298. pcaps->DesignatorMax = pbcaps->IsDesignatorRange ?
  1299. pbcaps->Range.DesignatorMax :
  1300. pbcaps->Range.DesignatorMin;
  1301. /*
  1302. * ISSUE-2001/03/06-MarcAnd What does IsAbsolute mean for a button?
  1303. */
  1304. pcaps->IsAbsolute = pbcaps->IsAbsolute;
  1305. AssertF(!pcaps->IsValue);
  1306. pcaps->type = type;
  1307. pcaps->IsAlias = pbcaps->IsAlias;
  1308. SquirtSqflPtszV(sqflVerbose | sqflHidParse,
  1309. TEXT("HidP_GetButtonCaps(%d)[%d]: ")
  1310. TEXT("Objs=%2d ")
  1311. TEXT("idx=%2d... ")
  1312. TEXT("coll=%d")
  1313. TEXT("IsAlias=%d"),
  1314. type, ibcaps,
  1315. pcaps->cObj,
  1316. pcaps->DataIndexMin,
  1317. pcaps->LinkCollection,
  1318. pcaps->IsAlias);
  1319. uiObj = this->rgdwBase[type] + pcaps->DataIndexMin;
  1320. for(duiObj = 0; duiObj < pcaps->cObj; duiObj++)
  1321. {
  1322. DWORD dwObjType;
  1323. LPDIOBJECTDATAFORMAT podf;
  1324. /*
  1325. * If HID messed up and gave us something out of range,
  1326. * then give up on this value caps (since the rest are
  1327. * also out of range) and move on to the next one.
  1328. */
  1329. if(uiObj + duiObj >= this->df.dwNumObjs)
  1330. {
  1331. RPF("HidP_GetButtonCaps inconsistent with NumberDataIndices - "
  1332. "skipping object (sorry)");
  1333. break;
  1334. }
  1335. AssertF(uiObj + duiObj < this->df.dwNumObjs);
  1336. if(this->rghoc[uiObj + duiObj].pcaps)
  1337. {
  1338. RPF("HidP_GetButtonCaps inconsistent - "
  1339. "can't use device");
  1340. hres = E_FAIL;
  1341. goto freedone;
  1342. }
  1343. /*
  1344. * No fatal errors have been detected so store the object details
  1345. */
  1346. AssertF( rgbReportIDs[uiObj + duiObj] == 0 );
  1347. rgbReportIDs[uiObj + duiObj] = pbcaps->ReportID;
  1348. this->rghoc[uiObj + duiObj].pcaps = pcaps;
  1349. podf = &this->df.rgodf[uiObj + duiObj];
  1350. /*
  1351. * Set a default instance. This will be overwritten later
  1352. * if this object is of a type we fully understand.
  1353. */
  1354. dwObjType = DIDFT_MAKEINSTANCE(uiObj + duiObj);
  1355. if(pcaps->UsagePage >= HID_USAGE_PAGE_VENDOR )
  1356. {
  1357. /*
  1358. * ISSUE-2001/03/06-MarcAnd vendor defined objects
  1359. * An aliased vendor defined usage may have a standard (not
  1360. * vendor defined) alias but the whole object will still be
  1361. * marked as vendor defined
  1362. */
  1363. if( pcaps->IsAlias )
  1364. {
  1365. dwObjType |= DIDFT_ALIAS;
  1366. }
  1367. dwObjType |= DIDFT_VENDORDEFINED;
  1368. podf->pguid = &GUID_Unknown;
  1369. }
  1370. else
  1371. {
  1372. if( pcaps->IsAlias )
  1373. {
  1374. dwObjType |= DIDFT_ALIAS;
  1375. }
  1376. /*
  1377. * In order to reduce the likelyhood of an app picking up a
  1378. * bit that is not a user controlled button, only mark bits
  1379. * as buttons if they are inputs on a usage page that
  1380. * contains such usages.
  1381. * ISSUE-2000/11/07-MarcAnd ideally we should be looking at
  1382. * not only the usage of the object but at the collections
  1383. * that contain it.
  1384. */
  1385. if( type == HidP_Input )
  1386. {
  1387. switch( pcaps->UsagePage )
  1388. {
  1389. case HID_USAGE_PAGE_KEYBOARD:
  1390. podf->pguid = &GUID_Key;
  1391. break;
  1392. case HID_USAGE_PAGE_BUTTON:
  1393. if( ( duiObj == 0 )
  1394. && ( pcaps->UsageMin == 0 ) )
  1395. {
  1396. /*
  1397. * Special case button zero means no buttons
  1398. * are pressed
  1399. */
  1400. SquirtSqflPtszV(sqfl | sqflTrace,
  1401. TEXT("Ignoring \"No button\" button") );
  1402. goto IgnoreButton;
  1403. }
  1404. case HID_USAGE_PAGE_GENERIC:
  1405. case HID_USAGE_PAGE_SIMULATION:
  1406. case HID_USAGE_PAGE_VR:
  1407. case HID_USAGE_PAGE_SPORT:
  1408. case HID_USAGE_PAGE_GAME:
  1409. case HID_USAGE_PAGE_CONSUMER:
  1410. case HID_USAGE_PAGE_DIGITIZER:
  1411. podf->pguid = &GUID_Button;
  1412. break;
  1413. default:
  1414. SquirtSqflPtszV(sqfl | sqflTrace,
  1415. TEXT("Assuming button 0x%04X:0x%04X is not a user control"),
  1416. pcaps->UsagePage,pcaps->UsageMin + duiObj );
  1417. goto IgnoreButton;
  1418. }
  1419. dwObjType |= DIDFT_PSHBUTTON;
  1420. if( !pcaps->IsAlias )
  1421. {
  1422. this->dwButtons++;
  1423. }
  1424. }
  1425. else
  1426. {
  1427. SquirtSqflPtszV(sqfl | sqflTrace,
  1428. TEXT("Assuming non-input bit 0x%04X:0x%04X is not a user control"),
  1429. pcaps->UsagePage,pcaps->UsageMin + duiObj );
  1430. IgnoreButton:;
  1431. podf->pguid = &GUID_Unknown;
  1432. }
  1433. }
  1434. /*
  1435. * Objects must have an offset to be accessed
  1436. */
  1437. podf->dwOfs = this->df.dwDataSize;
  1438. if( !pcaps->IsAlias)
  1439. {
  1440. this->df.dwDataSize += cbX(BYTE);
  1441. }
  1442. if(HidP_IsOutputLike(type))
  1443. {
  1444. /*
  1445. * Input and feature allow data; output does not.
  1446. */
  1447. if(type == HidP_Output)
  1448. {
  1449. dwObjType |= ( DIDFT_NODATA | DIDFT_OUTPUT );
  1450. }
  1451. else
  1452. {
  1453. dwObjType |= DIDFT_OUTPUT;
  1454. }
  1455. }
  1456. podf->dwType = dwObjType;
  1457. if(type != HidP_Input )
  1458. {
  1459. podf->dwFlags = DIDOI_POLLED | DIDOI_NOTINPUT;
  1460. } else if( this->IsPolledInput )
  1461. {
  1462. podf->dwFlags = DIDOI_POLLED;
  1463. } else
  1464. {
  1465. podf->dwFlags = 0;
  1466. }
  1467. /*
  1468. * ISSUE-2001/03/06-MarcAnd DIDOI FF attributes if not defined in registry
  1469. */
  1470. if( this->fPIDdevice
  1471. && ( dwObjType & DIDFT_PSHBUTTON ) )
  1472. {
  1473. podf->dwFlags |= DIDOI_FFEFFECTTRIGGER;
  1474. podf->dwType |= DIDFT_MAKEATTR(DIDOI_FFEFFECTTRIGGER);
  1475. }
  1476. }
  1477. D(pcaps->dwSignature = HIDGROUPCAPS_SIGNATURE);
  1478. }
  1479. hres = S_OK;
  1480. freedone:;
  1481. FreePv(rgbcaps);
  1482. done:;
  1483. return hres;
  1484. }
  1485. /*****************************************************************************
  1486. *
  1487. * @doc INTERNAL
  1488. *
  1489. * @method HRESULT | CHid | InitButtons |
  1490. *
  1491. * Identify and initialize the buttons: input, feature, and output.
  1492. *
  1493. * The input buttons come first, then the feature buttons,
  1494. * then the output buttons.
  1495. *
  1496. *****************************************************************************/
  1497. HRESULT INTERNAL
  1498. CHid_InitButtons(PCHID this)
  1499. {
  1500. HRESULT hres;
  1501. DWORD ccaps;
  1502. PBYTE rgbReportIDs;
  1503. UINT cbReportIDs;
  1504. UINT uMaxReportId;
  1505. this->ibButtonData = this->df.dwDataSize;
  1506. /*
  1507. * Skip over the value caps to get to the buttons ...
  1508. */
  1509. ccaps = this->caps.NumberInputValueCaps +
  1510. this->caps.NumberFeatureValueCaps +
  1511. this->caps.NumberOutputValueCaps;
  1512. /*
  1513. * Allocate a temporary buffer to store the report ID of each button.
  1514. * We use the sum of all data indices and collections so that the
  1515. * internal object index of each button can be used as the index into
  1516. * the buffer. We leave value and collection elements alone so they
  1517. * are just a small waste of space.
  1518. */
  1519. cbReportIDs = this->caps.NumberInputDataIndices +
  1520. this->caps.NumberFeatureDataIndices +
  1521. this->caps.NumberOutputDataIndices +
  1522. this->caps.NumberLinkCollectionNodes;
  1523. hres = AllocCbPpv( cbReportIDs, &rgbReportIDs );
  1524. if(FAILED(hres))
  1525. {
  1526. goto done;
  1527. }
  1528. /*
  1529. * Do the input buttons...
  1530. */
  1531. hres = CHid_InitButtonClass(this,
  1532. &this->rgcaps[ccaps],
  1533. rgbReportIDs,
  1534. this->caps.NumberInputButtonCaps,
  1535. HidP_Input);
  1536. if(FAILED(hres))
  1537. {
  1538. goto done;
  1539. }
  1540. ccaps += this->caps.NumberInputButtonCaps;
  1541. /*
  1542. * Do the feature buttons...
  1543. */
  1544. hres = CHid_InitButtonClass(this,
  1545. &this->rgcaps[ccaps],
  1546. rgbReportIDs,
  1547. this->caps.NumberFeatureButtonCaps,
  1548. HidP_Feature);
  1549. if(FAILED(hres))
  1550. {
  1551. goto done;
  1552. }
  1553. ccaps += this->caps.NumberFeatureButtonCaps;
  1554. /*
  1555. * Do the output buttons...
  1556. */
  1557. hres = CHid_InitButtonClass(this,
  1558. &this->rgcaps[ccaps],
  1559. rgbReportIDs,
  1560. this->caps.NumberOutputButtonCaps,
  1561. HidP_Output);
  1562. if(FAILED(hres))
  1563. {
  1564. goto done;
  1565. }
  1566. this->cbButtonData = this->df.dwDataSize - this->ibButtonData;
  1567. /*
  1568. * If this device only has one report ID, it must be ID zero
  1569. */
  1570. uMaxReportId = (UINT) max( this->wMaxReportId[HidP_Input],
  1571. max( this->wMaxReportId[HidP_Feature],
  1572. this->wMaxReportId[HidP_Output] ) );
  1573. /*
  1574. * If there's only one report or there are no buttons there's
  1575. * no need to set up the arrays of data masks for each report.
  1576. */
  1577. if( uMaxReportId == 0 )
  1578. {
  1579. AssertF( this->rgpbButtonMasks == NULL );
  1580. }
  1581. else if( this->cbButtonData == 0 )
  1582. {
  1583. AssertF( this->rgpbButtonMasks == NULL );
  1584. }
  1585. else
  1586. {
  1587. /*
  1588. * Allocate enough space for a mask array and a pointer to the array
  1589. * for each report.
  1590. */
  1591. hres = AllocCbPpv( uMaxReportId * ( this->cbButtonData + cbX( PV ) ),
  1592. &this->rgpbButtonMasks );
  1593. if( SUCCEEDED( hres ) )
  1594. {
  1595. UINT uReportId;
  1596. UINT uDataIdx;
  1597. UINT uBtnIdx;
  1598. UINT_PTR uCurrentMaskOfs;
  1599. /*
  1600. * The masks start after the last pointer to masks
  1601. */
  1602. uCurrentMaskOfs = uMaxReportId * cbX( this->rgpbButtonMasks[0] );
  1603. memset( (PBYTE)this->rgpbButtonMasks + uCurrentMaskOfs , 0xFF, this->cbButtonData * uMaxReportId );
  1604. /*
  1605. * Search through our temp buffer once for each report
  1606. */
  1607. for( uReportId=0; uReportId<uMaxReportId; uReportId++ )
  1608. {
  1609. for( uBtnIdx=uDataIdx=0; uDataIdx<cbReportIDs; uDataIdx++ )
  1610. {
  1611. /*
  1612. * Report IDs are one based but we use a zero based array
  1613. * so adjust when testing for a matching ID
  1614. */
  1615. if( rgbReportIDs[uDataIdx] == uReportId+1 )
  1616. {
  1617. /*
  1618. * Set the offset for this report to the current
  1619. * mask array. An offset is used so that when the
  1620. * memory is realloc'ed down to the size actually
  1621. * used, it is easier to generate pointers. If a
  1622. * report contains more than one button the same
  1623. * value will be set repeatedly.
  1624. */
  1625. this->rgpbButtonMasks[uReportId] = (PBYTE)uCurrentMaskOfs;
  1626. /*
  1627. * The final result is an AND mask so clear all bits
  1628. * so this button will be cleared when this report
  1629. * is being processed
  1630. */
  1631. ((PBYTE)this->rgpbButtonMasks)[uCurrentMaskOfs+uBtnIdx] = 0;
  1632. }
  1633. /*
  1634. * Just in case there are gaps in the HID report we
  1635. * use our own counter of button index which is only
  1636. * incremented when we find a button to keep in line
  1637. * with the contiguous block of buttons that we use.
  1638. */
  1639. if( rgbReportIDs[uDataIdx] != 0 )
  1640. {
  1641. uBtnIdx++;
  1642. AssertF( uBtnIdx <= this->cbButtonData );
  1643. }
  1644. }
  1645. /*
  1646. * There should always be exactly as many buttons in
  1647. * all the reports combined as we found when counting
  1648. * how many buttons there were of each type.
  1649. */
  1650. AssertF( uBtnIdx == this->cbButtonData );
  1651. /*
  1652. * If any buttons were found in this report, use next mask
  1653. */
  1654. if( this->rgpbButtonMasks[uReportId] == (PBYTE)uCurrentMaskOfs )
  1655. {
  1656. uCurrentMaskOfs += this->cbButtonData;
  1657. }
  1658. }
  1659. /*
  1660. * At least one report had to have a button in it.
  1661. */
  1662. AssertF( uCurrentMaskOfs != uMaxReportId * cbX( this->rgpbButtonMasks[0] ) );
  1663. /*
  1664. * Try to reduce the allocation to what we actually used
  1665. * In the worst case we only land up using excess memory
  1666. */
  1667. ReallocCbPpv( (UINT)uCurrentMaskOfs, &this->rgpbButtonMasks );
  1668. /*
  1669. * Convert the table of offsets into pointers
  1670. */
  1671. for( uReportId=0; uReportId<uMaxReportId; uReportId++ )
  1672. {
  1673. if( this->rgpbButtonMasks[uReportId] )
  1674. {
  1675. this->rgpbButtonMasks[uReportId] += (UINT_PTR)this->rgpbButtonMasks;
  1676. }
  1677. }
  1678. }
  1679. }
  1680. done:;
  1681. FreePpv( &rgbReportIDs );
  1682. return hres;
  1683. }
  1684. /*****************************************************************************
  1685. *
  1686. * @doc INTERNAL
  1687. *
  1688. * @method void | CHid | InitCollections |
  1689. *
  1690. * Identify and initialize the HID link collections.
  1691. *
  1692. *****************************************************************************/
  1693. HRESULT INTERNAL
  1694. CHid_InitCollections(PCHID this)
  1695. {
  1696. HRESULT hres;
  1697. NTSTATUS stat;
  1698. DWORD icoll, ccoll, ccaps;
  1699. PHIDP_LINK_COLLECTION_NODE rgcoll;
  1700. ccoll = this->caps.NumberLinkCollectionNodes;
  1701. /*
  1702. * Annoying quirk:
  1703. *
  1704. * HID doesn't like it when you pass 0 to HidP_GetLinkCollectionNodes,
  1705. * so we need to special-case the "no collections" scenario.
  1706. */
  1707. if(ccoll == 0)
  1708. {
  1709. hres = S_OK;
  1710. goto done;
  1711. }
  1712. hres = AllocCbPpv(cbCxX(ccoll, HIDP_LINK_COLLECTION_NODE), &rgcoll);
  1713. if(FAILED(hres))
  1714. {
  1715. goto done;
  1716. }
  1717. /*
  1718. * Get the collections...
  1719. */
  1720. stat = HidP_GetLinkCollectionNodes(rgcoll, &ccoll, this->ppd);
  1721. if(FAILED(stat))
  1722. {
  1723. RPF("HidP_GetLinkCollectionNodes failed - can't use device");
  1724. hres = E_FAIL;
  1725. goto freedone;
  1726. }
  1727. if(ccoll != this->caps.NumberLinkCollectionNodes)
  1728. {
  1729. RPF("HidP_GetLinkCollectionNodes inconsistent with HidP_GetCaps - "
  1730. "can't use device");
  1731. hres = E_FAIL;
  1732. goto freedone;
  1733. }
  1734. ccaps = this->caps.NumberInputValueCaps +
  1735. this->caps.NumberFeatureValueCaps +
  1736. this->caps.NumberOutputValueCaps +
  1737. this->caps.NumberInputButtonCaps +
  1738. this->caps.NumberFeatureButtonCaps +
  1739. this->caps.NumberOutputButtonCaps;
  1740. AssertF(ccaps + ccoll == this->ccaps);
  1741. for(icoll = 0; icoll < ccoll; icoll++)
  1742. {
  1743. PHIDP_LINK_COLLECTION_NODE pcoll = &rgcoll[icoll];
  1744. PHIDGROUPCAPS pcaps = &this->rgcaps[ccaps + icoll];
  1745. UINT uiObj;
  1746. LPDIOBJECTDATAFORMAT podf;
  1747. pcaps->UsagePage = pcoll->LinkUsagePage;
  1748. pcaps->UsageMin = pcoll->LinkUsage;
  1749. pcaps->cObj = 1;
  1750. pcaps->IsAlias = pcoll->IsAlias;
  1751. /*
  1752. * Not applicable for collections:
  1753. *
  1754. * StringMin/Max,
  1755. * DesignatorMin/Max,
  1756. * BitSize, LogicalMin/Max, PhysicalMin/Max, Units.
  1757. * IsAbsolute
  1758. */
  1759. pcaps->LinkCollection = pcoll->Parent;
  1760. pcaps->type = HidP_Coll;
  1761. /*
  1762. * We cook up DataIndexMin to correspond to this item.
  1763. */
  1764. pcaps->DataIndexMin = (USHORT)icoll;
  1765. uiObj = this->rgdwBase[HidP_Coll] + pcaps->DataIndexMin;
  1766. /*
  1767. * We generated these indices on our own, so they
  1768. * can't possible be wrong.
  1769. */
  1770. AssertF(uiObj < this->df.dwNumObjs);
  1771. this->rghoc[uiObj].pcaps = pcaps;
  1772. podf = &this->df.rgodf[uiObj];
  1773. /*
  1774. * ISSUE-2001/03/06-MarcAnd collections have GUID_Unknown
  1775. * Collections are more or less hidden and therefore unusable.
  1776. */
  1777. podf->pguid = &GUID_Unknown;
  1778. /*
  1779. * Set a default instance. This will be overwritten later
  1780. * if this object is of a type we fully understand.
  1781. */
  1782. podf->dwType = DIDFT_MAKEINSTANCE(uiObj) | DIDFT_COLLECTION | DIDFT_NODATA;
  1783. if(pcaps->UsagePage >= HID_USAGE_PAGE_VENDOR )
  1784. {
  1785. podf->dwType |= DIDFT_VENDORDEFINED;
  1786. }
  1787. podf->dwFlags = 0;
  1788. /*
  1789. * CHid_ObjFromType relies on dwCollections not being split between
  1790. * aliased and unaliased.
  1791. */
  1792. this->dwCollections++;
  1793. SquirtSqflPtszV(sqflVerbose | sqflHidParse,
  1794. TEXT("HidP_GetLinkCollectionNodes(%d)[%d]: ")
  1795. TEXT("Objs=%2d ")
  1796. TEXT("idx=%2d... ")
  1797. TEXT("coll=%d")
  1798. TEXT("IsAlias=%d"),
  1799. pcaps->type, icoll,
  1800. pcaps->cObj,
  1801. pcaps->DataIndexMin,
  1802. pcaps->LinkCollection,
  1803. pcaps->IsAlias);
  1804. D(pcaps->dwSignature = HIDGROUPCAPS_SIGNATURE);
  1805. }
  1806. hres = S_OK;
  1807. freedone:;
  1808. FreePv(rgcoll);
  1809. done:;
  1810. return hres;
  1811. }
  1812. /*****************************************************************************
  1813. *
  1814. * @doc INTERNAL
  1815. *
  1816. * @method HRESULT | CHid | AllocObjectMemory |
  1817. *
  1818. * Allocate all the memory that will be used to store object
  1819. * information.
  1820. *
  1821. *****************************************************************************/
  1822. HRESULT INTERNAL
  1823. CHid_AllocObjectMemory(PCHID this)
  1824. {
  1825. DWORD cb;
  1826. DWORD cvcaps, cbcaps, ccoll, cjrc;
  1827. HRESULT hres;
  1828. /*
  1829. * Some trace squirties because HID is tricky.
  1830. */
  1831. SquirtSqflPtszV(sqflVerbose | sqflHidParse,
  1832. TEXT("HidP_GetCaps: NumberInputDataIndices = %d"),
  1833. this->caps.NumberInputDataIndices);
  1834. SquirtSqflPtszV(sqflVerbose | sqflHidParse,
  1835. TEXT("HidP_GetCaps: NumberOutputDataIndices = %d"),
  1836. this->caps.NumberOutputDataIndices);
  1837. SquirtSqflPtszV(sqflVerbose | sqflHidParse,
  1838. TEXT("HidP_GetCaps: NumberFeatureDataIndices = %d"),
  1839. this->caps.NumberFeatureDataIndices);
  1840. SquirtSqflPtszV(sqflVerbose | sqflHidParse,
  1841. TEXT("HidP_GetCaps: NumberLinkCollectionNodes = %d"),
  1842. this->caps.NumberLinkCollectionNodes);
  1843. SquirtSqflPtszV(sqflVerbose | sqflHidParse,
  1844. TEXT("HidP_GetCaps: NumberInputValueCaps = %d"),
  1845. this->caps.NumberInputValueCaps);
  1846. SquirtSqflPtszV(sqflVerbose | sqflHidParse,
  1847. TEXT("HidP_GetCaps: NumberOutputValueCaps = %d"),
  1848. this->caps.NumberOutputValueCaps);
  1849. SquirtSqflPtszV(sqflVerbose | sqflHidParse,
  1850. TEXT("HidP_GetCaps: NumberFeatureValueCaps = %d"),
  1851. this->caps.NumberFeatureValueCaps);
  1852. SquirtSqflPtszV(sqflVerbose | sqflHidParse,
  1853. TEXT("HidP_GetCaps: NumberInputButtonCaps = %d"),
  1854. this->caps.NumberInputButtonCaps);
  1855. SquirtSqflPtszV(sqflVerbose | sqflHidParse,
  1856. TEXT("HidP_GetCaps: NumberOutputButtonCaps = %d"),
  1857. this->caps.NumberOutputButtonCaps);
  1858. SquirtSqflPtszV(sqflVerbose | sqflHidParse,
  1859. TEXT("HidP_GetCaps: NumberFeatureButtonCaps = %d"),
  1860. this->caps.NumberFeatureButtonCaps);
  1861. /*
  1862. * Allocate the memory into which we place
  1863. * the DIOBJECTDATAFORMATs we build.
  1864. */
  1865. this->df.dwNumObjs = this->caps.NumberInputDataIndices +
  1866. this->caps.NumberOutputDataIndices +
  1867. this->caps.NumberFeatureDataIndices +
  1868. this->caps.NumberLinkCollectionNodes;
  1869. if(this->df.dwNumObjs >= DIDFT_GETINSTANCE(DIDFT_ANYINSTANCE))
  1870. {
  1871. ("Too many objects in HID device (%d) - can't use device",
  1872. this->df.dwNumObjs);
  1873. hres = E_FAIL;
  1874. goto done;
  1875. }
  1876. SquirtSqflPtszV(sqflHidParse,
  1877. TEXT("CHid_AllocObjectMemory: dwNumObjs = %d"),
  1878. this->df.dwNumObjs);
  1879. /*
  1880. * ISSUE-2001/10/17-MarcAnd Axes declared in ranges cause AVs
  1881. * We only allocate as many JOYRANGECONVERT elements as there are value
  1882. * caps in HID but multiple axes may be declared in a range which will
  1883. * be reported in a single value caps.
  1884. */
  1885. cjrc = this->caps.NumberInputValueCaps;
  1886. cvcaps = this->caps.NumberInputValueCaps +
  1887. this->caps.NumberFeatureValueCaps +
  1888. this->caps.NumberOutputValueCaps;
  1889. cbcaps = this->caps.NumberInputButtonCaps +
  1890. this->caps.NumberFeatureButtonCaps +
  1891. this->caps.NumberOutputButtonCaps;
  1892. ccoll = this->caps.NumberLinkCollectionNodes;
  1893. this->ccaps = cvcaps + cbcaps + ccoll;
  1894. /*
  1895. * Allocating the memory is done in four phases.
  1896. *
  1897. * 1. Tally up how much memory we need,
  1898. * 2. Allocate that memory,
  1899. * 3. Dole out the memory we allocated,
  1900. * 4. Check that we didn't mess up.
  1901. *
  1902. * Since this is extremely error-prone (I've messed it up at least
  1903. * once), the work is hidden inside macros.
  1904. *
  1905. * The macro THINGS expands to a series of THING()s, each of which
  1906. * specifies a field name and the size it should be. Each time you
  1907. * want to iterate over the fields, use the THINGS macro.
  1908. */
  1909. #define THINGS() \
  1910. THING(df.rgodf, cbCxX(this->df.dwNumObjs, DIOBJECTDATAFORMAT)); \
  1911. THING(rghoc, cbCxX(this->df.dwNumObjs, HIDOBJCAPS)); \
  1912. THING(rgcaps, cbCxX(this->ccaps, HIDGROUPCAPS)); \
  1913. THING(pjrcNext, cbCxX(cjrc, JOYRANGECONVERT)); \
  1914. /*
  1915. * Make a pass through the fields adding up the memory requirements.
  1916. */
  1917. #define THING(f, cbF) cb += cbF
  1918. cb = 0;
  1919. THINGS();
  1920. #undef THING
  1921. hres = ReallocCbPpv(cb, &this->df.rgodf);
  1922. if(SUCCEEDED(hres))
  1923. {
  1924. PV pv;
  1925. /*
  1926. * Make a pass through the fields carving up the memory block
  1927. * and handing out pieces of it.
  1928. */
  1929. #define THING(f, cbF) this->f = pv; pv = pvAddPvCb(pv, cbF)
  1930. pv = this->df.rgodf;
  1931. THINGS();
  1932. #undef THING
  1933. /*
  1934. * There should be no byte left over.
  1935. */
  1936. AssertF(pvAddPvCb(this->df.rgodf, cb) == pv);
  1937. }
  1938. #undef THINGS
  1939. SquirtSqflPtszV(sqflHidParse,
  1940. TEXT("CHid_AllocObjectMemory: pv = %08x, cb = 0x%08x"),
  1941. this->df.rgodf, cb);
  1942. done:;
  1943. return hres;
  1944. }
  1945. /*****************************************************************************
  1946. *
  1947. * @doc INTERNAL
  1948. *
  1949. * @method HRESULT | CHid | EnumKeyboardMunge |
  1950. *
  1951. * Enumerate the objects in the list, indicating whether
  1952. * each object is "keyboardlike" or "otherlike".
  1953. *
  1954. * @parm LPBYTE | pb |
  1955. *
  1956. * Pointer to translation table that converts HID usages
  1957. * into keyboard scan codes.
  1958. *
  1959. * @parm KBDMUNGECALLBACK | Munge |
  1960. *
  1961. * Callback function that handles each object as we find it.
  1962. *
  1963. * @parm PV | pvRef |
  1964. *
  1965. * Reference data for callback.
  1966. *
  1967. * @cb void CALLBACK | KbdMungeCallback |
  1968. *
  1969. * Called once for each object on a keyboard HID device.
  1970. *
  1971. * @parm PCHID | this |
  1972. *
  1973. * The device itself.
  1974. *
  1975. * @parm UINT | uiObj |
  1976. *
  1977. * The object being enumerated.
  1978. *
  1979. * @parm UINT | dik |
  1980. *
  1981. * DirectInput scan code for the object, or a value greater than
  1982. * or equal to <c DIKBD_CKEYS> if it's a fake instance number
  1983. * concocted for a non-AT key.
  1984. *
  1985. *****************************************************************************/
  1986. typedef void (CALLBACK *KBDMUNGECALLBACK)(PCHID this, UINT uiObj, UINT dik);
  1987. void INTERNAL
  1988. CHid_EnumKeyboardMunge(PCHID this, LPBYTE pb, KBDMUNGECALLBACK Munge)
  1989. {
  1990. UINT uiObj;
  1991. BYTE rgbSeen[DIKBD_CKEYS];
  1992. UINT uiCollections;
  1993. /*
  1994. * In principle we could walk the this->rgcaps array, but
  1995. * that would open the risk that the this->rgcaps array
  1996. * and this->df.rgodf array are out of sync for some
  1997. * bizarre reason. Do it the slow way just to be safe.
  1998. *
  1999. * Furthermore, only the first item with a particular
  2000. * keyboard usage gets mapped into the DirectInput table.
  2001. * So if a keyboard has two ESCAPE keys, only the first
  2002. * one shows up in the DirectInput table; the second one
  2003. * shows up as "just another key".
  2004. */
  2005. this->uiInstanceMax = DIKBD_CKEYS;
  2006. ZeroX(rgbSeen);
  2007. for(uiCollections = uiObj = 0; uiObj < this->df.dwNumObjs; uiObj++)
  2008. {
  2009. PHIDGROUPCAPS pcaps;
  2010. UINT dik;
  2011. UINT duiObj;
  2012. UINT DataIndex;
  2013. UINT Usage;
  2014. pcaps = this->rghoc[uiObj].pcaps;
  2015. if( pcaps->type == HidP_Coll )
  2016. {
  2017. dik = uiCollections++;
  2018. }
  2019. else
  2020. {
  2021. AssertF( HidP_IsValidReportType(pcaps->type) );
  2022. DataIndex = uiObj - this->rgdwBase[pcaps->type];
  2023. duiObj = DataIndex - pcaps->DataIndexMin;
  2024. AssertF(duiObj < pcaps->cObj);
  2025. Usage = pcaps->UsageMin + duiObj;
  2026. if(pcaps->UsagePage == HID_USAGE_PAGE_KEYBOARD)
  2027. {
  2028. if(Usage < DIKBD_CKEYS && pb[Usage] && !rgbSeen[pb[Usage]])
  2029. {
  2030. rgbSeen[pb[Usage]] = 1;
  2031. dik = pb[Usage];
  2032. } else
  2033. {
  2034. dik = this->uiInstanceMax++;
  2035. }
  2036. } else
  2037. {
  2038. dik = this->uiInstanceMax++;
  2039. }
  2040. }
  2041. Munge(this, uiObj, dik);
  2042. }
  2043. }
  2044. /*****************************************************************************
  2045. *
  2046. * @doc INTERNAL
  2047. *
  2048. * @method void | CHid | TallyKeyboardObjs |
  2049. *
  2050. * Callback function used during preliminary tallying to
  2051. * tot up how many of the objects can be treated as
  2052. * AT-compatible keyboard gizmos and how many are HID-specific.
  2053. *
  2054. * @parm UINT | uiObj |
  2055. *
  2056. * The object being enumerated.
  2057. *
  2058. * @parm UINT | dik |
  2059. *
  2060. * DirectInput scan code for the object, or a value greater than
  2061. * or equal to <c DIKBD_CKEYS> if it's a fake instance number
  2062. * concocted for a non-AT key.
  2063. *
  2064. *****************************************************************************/
  2065. void INTERNAL
  2066. CHid_TallyKeyboardObjs(PCHID this, UINT uiObj, UINT dik)
  2067. {
  2068. this;
  2069. uiObj;
  2070. dik;
  2071. }
  2072. /*****************************************************************************
  2073. *
  2074. * @doc INTERNAL
  2075. *
  2076. * @method void | CHid | ReassignKeyboardObjs |
  2077. *
  2078. * Callback function used to shuffle instance numbers around
  2079. * to make them AT-compatible when possible.
  2080. *
  2081. * @parm UINT | uiObj |
  2082. *
  2083. * The object being enumerated.
  2084. *
  2085. * @parm UINT | dik |
  2086. *
  2087. * DirectInput scan code for the object, or a value greater than
  2088. * or equal to <c DIKBD_CKEYS> if it's a fake instance number
  2089. * concocted for a non-AT key or an index number for a collection.
  2090. *
  2091. *****************************************************************************/
  2092. void INTERNAL
  2093. CHid_ReassignKeyboardObjs(PCHID this, UINT uiObj, UINT dik)
  2094. {
  2095. if( this->df.rgodf[uiObj].dwType & DIDFT_COLLECTION )
  2096. {
  2097. this->rgicoll[dik] = uiObj;
  2098. }
  2099. else
  2100. {
  2101. this->rgiobj[dik] = uiObj;
  2102. }
  2103. SquirtSqflPtszV(sqfl | sqflVerbose,
  2104. TEXT("CHid_ReassignKeyboardObjs: ")
  2105. TEXT("uiObj = %03x, dwType = %08x, dik=%04x"),
  2106. uiObj, this->df.rgodf[uiObj].dwType,
  2107. dik);
  2108. this->df.rgodf[uiObj].dwType =
  2109. (this->df.rgodf[uiObj].dwType & ~DIDFT_INSTANCEMASK) |
  2110. DIDFT_MAKEINSTANCE(dik);
  2111. }
  2112. /*****************************************************************************
  2113. *
  2114. * @doc INTERNAL
  2115. *
  2116. * @method HRESULT | CHid | MungeKeyboard |
  2117. *
  2118. * We just created a keyboard device.
  2119. *
  2120. * Unfortunately, DirectInput has some annoying requirements
  2121. * for keyboard devices, so here is where we swizzle the instance
  2122. * numbers around to keep DirectInput happy.
  2123. *
  2124. *****************************************************************************/
  2125. HRESULT INTERNAL
  2126. CHid_MungeKeyboard(PCHID this)
  2127. {
  2128. HRESULT hres;
  2129. LPBYTE pb;
  2130. AssertF(this->rgiobj == 0);
  2131. pb = pvFindResource(g_hinst, IDDATA_HIDMAP, RT_RCDATA);
  2132. if(pb)
  2133. {
  2134. /*
  2135. * Count up the number of non-keyboard things on this device.
  2136. * They will get instance numbers starting at DIKBD_CKEYS.
  2137. */
  2138. CHid_EnumKeyboardMunge(this, pb, CHid_TallyKeyboardObjs);
  2139. /*
  2140. * Now that we know how many nonstandard keyboard thingies
  2141. * we have, allocate room for the translation table
  2142. * and work all the instance values around to keep
  2143. * legacy apps happy.
  2144. */
  2145. hres = ReallocCbPpv(cbCdw(this->uiInstanceMax + this->dwCollections), &this->rgiobj);
  2146. if(SUCCEEDED(hres))
  2147. {
  2148. memset(this->rgiobj, 0xFF, cbCxX(this->uiInstanceMax + this->dwCollections, INT));
  2149. /*
  2150. * In case a keyboard comes along with non-button inputs,
  2151. * set up the other types of pointers to the same buffer.
  2152. */
  2153. this->rgipov = this->rgiaxis = this->rgiobj;
  2154. /*
  2155. * Put collections at the end, there should be at least one
  2156. */
  2157. AssertF( this->dwCollections );
  2158. this->rgicoll = &this->rgiobj[this->uiInstanceMax];
  2159. CHid_EnumKeyboardMunge(this, pb, CHid_ReassignKeyboardObjs);
  2160. hres = S_OK;
  2161. }
  2162. /*
  2163. * Prefix warns that the resource is leaked (mb:34650) but there is
  2164. * no API to release a raw resource (FreeResource is a stub) so there
  2165. * is nothing we can do.
  2166. */
  2167. } else
  2168. {
  2169. hres = E_FAIL;
  2170. }
  2171. return hres;
  2172. }
  2173. /*****************************************************************************
  2174. *
  2175. * @doc INTERNAL
  2176. *
  2177. * @method HRESULT | CHid | MungeNotKeyboard |
  2178. *
  2179. * We just created a device that is not a keyboard.
  2180. *
  2181. * Since we need the instance for each object to be relative only to
  2182. * objects of that type, we need to replace the device relative
  2183. * values generated into type relative ones. In addition, to
  2184. * maintain compatability with pre-HID object instances we need to
  2185. * use axis instance numbers that would be generated for a WinMM
  2186. * mapped axis.
  2187. * Aliased objects must be given the same instance number as the
  2188. * primary alias so that the only difference between them is their
  2189. * usage. This prevents a data format being generated using multiple
  2190. * aliases of the same object.
  2191. *
  2192. * ISSUE-2001/03/13-MarcAnd HID object munging is incomplete
  2193. * 1. Multiple values on a single axis (force and position)
  2194. * 2. Multiple instances of an axis type (two throttles)
  2195. * 3. Does not distinguish output only values (actuators) from axes
  2196. * 4. Keyboards with anything other than buttons should have this
  2197. * done but won't
  2198. *
  2199. *****************************************************************************/
  2200. /*
  2201. * Internal function to convert all the attributes of one object to another
  2202. *
  2203. * If an axis needs to be reinterpreted here, both the axis semantic and the
  2204. * object GUID need to be changed so that the axis will be used consistently
  2205. * in both semantic mapper and data format games.
  2206. *
  2207. * Note, multiple instances of an axis type are not handled well.
  2208. */
  2209. void INTERNAL ReinterpretObject
  2210. (
  2211. PCHID this,
  2212. PDWORD pdwHints,
  2213. int cAxes,
  2214. PDWORD pdwTypeFlags,
  2215. DWORD dwSrcHint,
  2216. DWORD dwDstHint,
  2217. BYTE bSemFlags,
  2218. PCGUID pgNew
  2219. )
  2220. {
  2221. if( ( *pdwTypeFlags & ( dwSrcHint | dwDstHint ) ) == dwSrcHint )
  2222. {
  2223. int idx;
  2224. for( idx = 0; idx < cAxes + 6; idx++ )
  2225. {
  2226. if( pdwHints[idx] == dwSrcHint )
  2227. {
  2228. *pdwTypeFlags ^= ( dwSrcHint | dwDstHint );
  2229. pdwHints[idx] = dwDstHint;
  2230. this->rgbaxissemflags[idx] = bSemFlags;
  2231. this->df.rgodf[this->rgiaxis[idx]].pguid = pgNew;
  2232. break;
  2233. }
  2234. }
  2235. AssertF( idx < cAxes + 6 );
  2236. }
  2237. }
  2238. HRESULT INTERNAL
  2239. CHid_MungeNotKeyboard(PCHID this)
  2240. {
  2241. HRESULT hres;
  2242. unsigned int uiObj;
  2243. int iButton;
  2244. int iCollection = 0;
  2245. int iPOV = 0;
  2246. int iAxis = 0;
  2247. //to indicate the index of the last "actual" button
  2248. int iLastButtonIndex = 0;
  2249. //to indicate the number of "non-actual" buttons
  2250. int iOtherButton = 0;
  2251. PINT piRemap = 0;
  2252. BOOL fCarController = FALSE;
  2253. DWORD dwTypeFlags = 0;
  2254. int cAxes;
  2255. D( iButton = 0; )
  2256. AssertF(this->rgiobj == 0);
  2257. /*
  2258. * First count the distinct types so we know how to segment rgiobj
  2259. */
  2260. for(uiObj = 0; uiObj < this->df.dwNumObjs; uiObj++)
  2261. {
  2262. SquirtSqflPtszV(sqflHidParse | sqflVerbose,
  2263. TEXT("CHid_MungeNotKeyboard: uiObj: %d starts as dwType 0x%08x"),
  2264. uiObj, this->df.rgodf[uiObj].dwType );
  2265. if( !this->rghoc[uiObj].pcaps )
  2266. {
  2267. continue;
  2268. }
  2269. if( this->rghoc[uiObj].pcaps->IsAlias )
  2270. {
  2271. /*
  2272. * If there's a steering wheel anywhere, we need to know
  2273. */
  2274. if( ( DIDFT_AXIS == ( this->df.rgodf[uiObj].dwType & ( DIDFT_AXIS | DIDFT_NODATA ) ) )
  2275. && ( this->rghoc[uiObj].pcaps->UsagePage == HID_USAGE_PAGE_SIMULATION )
  2276. && ( HID_USAGE_SIMULATION_STEERING ==
  2277. ( this->rghoc[uiObj].pcaps->UsageMin + uiObj
  2278. - this->rgdwBase[this->rghoc[uiObj].pcaps->type]
  2279. - this->rghoc[uiObj].pcaps->DataIndexMin ) ) )
  2280. {
  2281. fCarController = TRUE;
  2282. }
  2283. continue;
  2284. }
  2285. /*
  2286. * Don't bother taking pointer to dwType in this simple
  2287. * loop as it should be enregistered anyway.
  2288. */
  2289. if( this->df.rgodf[uiObj].dwType & DIDFT_COLLECTION )
  2290. {
  2291. iCollection++;
  2292. }
  2293. else if( this->df.rgodf[uiObj].dwType & DIDFT_NODATA )
  2294. {
  2295. /*
  2296. * Don't count objects that report no data
  2297. */
  2298. continue;
  2299. }
  2300. else if( this->df.rgodf[uiObj].dwType & DIDFT_BUTTON )
  2301. {
  2302. //HID reports everything that has size 1 bit as a button.
  2303. //We need to know the index of the highest "actual" button -- the one that has USAGE_PAGE_BUTTON
  2304. //And then we also need to know how many "non-actual" buttons there are.
  2305. //The total amount of memory we need to allocate for buttons is the sum of those 2.
  2306. if (this->rghoc[uiObj].pcaps->UsagePage == HID_USAGE_PAGE_BUTTON)
  2307. {
  2308. int iUsage = ( this->rghoc[uiObj].pcaps->UsageMin
  2309. + uiObj
  2310. - this->rgdwBase[this->rghoc[uiObj].pcaps->type]
  2311. - this->rghoc[uiObj].pcaps->DataIndexMin );
  2312. if (iUsage > iLastButtonIndex)
  2313. {
  2314. iLastButtonIndex = iUsage;
  2315. }
  2316. }
  2317. else
  2318. {
  2319. iOtherButton++;
  2320. }
  2321. D( iButton++; )
  2322. }
  2323. else if( this->df.rgodf[uiObj].dwType & DIDFT_AXIS )
  2324. {
  2325. iAxis++;
  2326. }
  2327. else if( this->df.rgodf[uiObj].dwType & DIDFT_POV )
  2328. {
  2329. iPOV++;
  2330. }
  2331. }
  2332. /*
  2333. * Assert that we counted everything OK while we have a button count
  2334. */
  2335. AssertF( (int)this->df.dwNumObjs >= ( iPOV + iButton + iAxis + iCollection ) );
  2336. /*
  2337. * The total amount of memory we need to allocate for buttons is the sum of
  2338. * the highest "actual" button index and the number of "non-actual" buttons.
  2339. */
  2340. iButton = iOtherButton + iLastButtonIndex;
  2341. AssertF(iButton >= 0);
  2342. /*
  2343. * You can go to a whole lot of trouble finding out exactly what gaps
  2344. * are left by the WinMM mapping but in the end, it's only 24 bytes of
  2345. * data and it takes way more to work out how to save them.
  2346. * So just allocate 6 extra in case all the axes are non-WinMM.
  2347. * Note, there is weirdnes involved in WinMM axes as a real WinMM device
  2348. * always have the U (Ry) and V (Rx) axes mapped to S0 and S1 however HID
  2349. * devices have more flexible mappings. Since the main reason to try to
  2350. * keep WinMM and HID axes the same is for FF, only X and Y are critical.
  2351. * Keep the button count in cAxes so we can reference it when we need to
  2352. * without worrying about whether iAxis is the current max or the real
  2353. * max. Should do this for the other counts as well but that can wait
  2354. * until this function gets its long overdue restructuring.
  2355. */
  2356. cAxes = iAxis;
  2357. this->uiInstanceMax = iCollection + iButton + cAxes + iPOV + 6;
  2358. /*
  2359. * Note, piRemap received a pointer to a buffer user for workspace.
  2360. * The single allocation is subdivided as follows:
  2361. * a buffer for an array of ints for matched objects,
  2362. * an array of USAGES for axes and
  2363. * and array of DWORDs for hint flags.
  2364. */
  2365. if( SUCCEEDED( hres = ReallocCbPpv(cbCdw(this->uiInstanceMax), &this->rgiobj) )
  2366. && SUCCEEDED( hres = AllocCbPpv( ( cbCdw( 2 * (cAxes + 6) ) + cbCxX(this->uiInstanceMax, INT) ), &piRemap ) )
  2367. && SUCCEEDED( hres = AllocCbPpv( cAxes + 6, &this->rgbaxissemflags ) ) )
  2368. {
  2369. /*
  2370. * NOTE - this is not the order they are stored in the registry - but the macro used for
  2371. * generating them internally has been reversed somewhere along the track.
  2372. */
  2373. typedef union _USAGES
  2374. {
  2375. struct
  2376. {
  2377. USAGE Usage;
  2378. USAGE UsagePage;
  2379. };
  2380. DWORD dwUsages;
  2381. } USAGES, *PUSAGES;
  2382. PUSAGES pUsageMatches;
  2383. PDWORD pdwHints;
  2384. int iNops = 0;
  2385. int iUsages = 0;
  2386. int iAxisIdx;
  2387. HKEY hkAxis;
  2388. DWORD dwTestType = 0;
  2389. int iTypeAxes = 0;
  2390. BOOL bAllMatch=TRUE;
  2391. ZeroMemory( this->rgbaxissemflags, cAxes + 6 );
  2392. memset(piRemap, 0xFF, cbCxX(this->uiInstanceMax, INT));
  2393. memset(this->rgiobj, 0xFF, cbCxX(this->uiInstanceMax, INT));
  2394. /*
  2395. * CHid_ObjFromType relies on the order of these for range checking
  2396. */
  2397. this->rgipov = &this->rgiobj[iButton];
  2398. this->rgiaxis = &this->rgipov[iPOV];
  2399. this->rgicoll = &this->rgipov[cAxes+6];
  2400. /*
  2401. * In order to allow IHVs to describe their devices with usages
  2402. * that we don't have in our table but still work for legacy apps, we
  2403. * allow axes to be selected using the DIOBJECTATTRIBUTES in the
  2404. * registry.
  2405. */
  2406. pUsageMatches = (PUSAGES)&piRemap[this->uiInstanceMax];
  2407. pdwHints = &pUsageMatches[cAxes + 6].dwUsages;
  2408. /*
  2409. * Assert that we can treat the combined usage page / usage
  2410. * WORDs using a union of a DWORD and two WORDs.
  2411. CAssertF( ( FIELD_OFFSET( DIOBJECTATTRIBUTES, wUsage )
  2412. - FIELD_OFFSET( DIOBJECTATTRIBUTES, wUsagePage ) )
  2413. == ( FIELD_OFFSET( USAGES, Usage )
  2414. - FIELD_OFFSET( USAGES, UsagePage ) ) );
  2415. */
  2416. /*
  2417. * Fetch IHV matches for all reasonable axes.
  2418. */
  2419. for( iAxisIdx = 0; iAxisIdx < cAxes + 5; iAxisIdx++ )
  2420. {
  2421. if( SUCCEEDED( CType_OpenIdSubkey( this->hkType,
  2422. DIDFT_AXIS | DIDFT_MAKEINSTANCE( iAxisIdx ),
  2423. KEY_QUERY_VALUE, &hkAxis ) ) )
  2424. {
  2425. DIOBJECTATTRIBUTES attr;
  2426. if( ( SUCCEEDED( JoyReg_GetValue( hkAxis, TEXT("Attributes"),
  2427. REG_BINARY, &attr, cbX(attr) ) ) )
  2428. && ( *(PDWORD)&attr.wUsagePage ) )
  2429. {
  2430. pUsageMatches[iAxisIdx].UsagePage = attr.wUsagePage;
  2431. pUsageMatches[iAxisIdx].Usage = attr.wUsage;
  2432. iUsages++;
  2433. /*
  2434. * Check it really exists on the device
  2435. * New behaviour is to ignore ALL registry mappings
  2436. * and dfault to DX7 implementation if a bogus
  2437. * control is found
  2438. */
  2439. for(uiObj = 0; uiObj < this->df.dwNumObjs; uiObj++)
  2440. {
  2441. if( ( this->df.rgodf[uiObj].dwType & DIDFT_AXIS )
  2442. && ( this->rghoc[uiObj].pcaps )
  2443. && ( this->rghoc[uiObj].pcaps->type == HidP_Input ) )
  2444. {
  2445. USAGES Usages;
  2446. UINT uidObj;
  2447. Usages.UsagePage = this->rghoc[uiObj].pcaps->UsagePage;
  2448. uidObj = uiObj - ( this->rgdwBase[HidP_Input] + this->rghoc[uiObj].pcaps->DataIndexMin );
  2449. Usages.Usage = this->rghoc[uiObj].pcaps->UsageMin + uidObj;
  2450. if( Usages.dwUsages == pUsageMatches[iAxisIdx].dwUsages )
  2451. {
  2452. SquirtSqflPtszV(sqfl | sqflVerbose,
  2453. TEXT("CHid_MungeNotKeyboard: Object %d matches 0x%08x"),
  2454. uiObj, pUsageMatches[iAxisIdx].dwUsages );
  2455. break;
  2456. }
  2457. }
  2458. }
  2459. if (uiObj >= this->df.dwNumObjs)
  2460. {
  2461. //Error in registry settings - usage/usagepage pair not present on device
  2462. //reset
  2463. SquirtSqflPtszV(sqfl | sqflVerbose,
  2464. TEXT("CHid_MungeNotKeyboard: No matches for 0x%08x - abandoning IHV map"),
  2465. pUsageMatches[iAxisIdx].dwUsages );
  2466. iUsages=0;
  2467. memset(piRemap, 0xFF, cbCxX(this->uiInstanceMax, INT));
  2468. bAllMatch=FALSE;
  2469. break;
  2470. }
  2471. }
  2472. else
  2473. {
  2474. iNops++;
  2475. }
  2476. RegCloseKey( hkAxis );
  2477. if( iUsages + iNops == cAxes )
  2478. {
  2479. /*
  2480. * We've opened as many keys as we have axes
  2481. * continue the loop in debug as sanity check.
  2482. */
  2483. #ifdef XDEBUG
  2484. int iDbgIdx;
  2485. for( iDbgIdx = iAxisIdx + 1; iDbgIdx < cAxes + 5; iDbgIdx++ )
  2486. {
  2487. if( SUCCEEDED( CType_OpenIdSubkey( this->hkType,
  2488. DIDFT_AXIS | DIDFT_MAKEINSTANCE( iDbgIdx ),
  2489. KEY_QUERY_VALUE, &hkAxis ) ) )
  2490. {
  2491. RPF( "More axis keys than axes on device %04x:%04x!",
  2492. this->VendorID, this->ProductID );
  2493. }
  2494. }
  2495. #endif
  2496. break;
  2497. }
  2498. }
  2499. }
  2500. /*
  2501. * Go through all input axes, including aliases, trying to find a match
  2502. */
  2503. for(uiObj = 0; uiObj < this->df.dwNumObjs && bAllMatch; uiObj++)
  2504. {
  2505. UINT uiObjPrimary;
  2506. int iUsageIdx;
  2507. if( ( this->df.rgodf[uiObj].dwType & DIDFT_AXIS )
  2508. && ( this->rghoc[uiObj].pcaps )
  2509. && ( this->rghoc[uiObj].pcaps->type == HidP_Input ) )
  2510. {
  2511. USAGES Usages;
  2512. UINT uidObj;
  2513. if( !this->rghoc[uiObj].pcaps->IsAlias )
  2514. {
  2515. uiObjPrimary = uiObj;
  2516. }
  2517. Usages.UsagePage = this->rghoc[uiObj].pcaps->UsagePage;
  2518. uidObj = uiObj - ( this->rgdwBase[HidP_Input] + this->rghoc[uiObj].pcaps->DataIndexMin );
  2519. Usages.Usage = this->rghoc[uiObj].pcaps->UsageMin + uidObj;
  2520. /*
  2521. * Use incremental loop for better JoyHID consistency
  2522. */
  2523. for( iUsageIdx = 0; iUsageIdx <= iAxisIdx; iUsageIdx++ )
  2524. {
  2525. if( Usages.dwUsages == pUsageMatches[iUsageIdx].dwUsages )
  2526. {
  2527. PHIDUSAGEMAP phum;
  2528. LPDIOBJECTDATAFORMAT podf;
  2529. /*
  2530. * Remember this one for later and
  2531. * discount it from further matches.
  2532. */
  2533. piRemap[uiObjPrimary] = iUsageIdx;
  2534. pUsageMatches[iUsageIdx].dwUsages = 0;
  2535. /*
  2536. * Try to fix up the object GUID
  2537. * Use a usage page usage match if possible
  2538. * otherwise pretend this is a generic axis
  2539. * of the appropriate type or settle for
  2540. * unknown.
  2541. */
  2542. podf = &this->df.rgodf[uiObj + uidObj];
  2543. if( iUsageIdx < 6 )
  2544. {
  2545. phum = UsageToUsageMap( DIMAKEUSAGEDWORD(
  2546. HID_USAGE_PAGE_GENERIC, HID_USAGE_GENERIC_X + iUsageIdx ) );
  2547. AssertF( phum );
  2548. podf->pguid = phum->pguid;
  2549. this->rgbaxissemflags[iUsageIdx] = phum->bSemFlag;
  2550. pdwHints[iUsageIdx] = phum->dwSemHint;
  2551. dwTypeFlags |= phum->dwSemHint;
  2552. }
  2553. else if (iUsageIdx < 8)
  2554. {
  2555. podf->pguid = &GUID_Slider;
  2556. this->rgbaxissemflags[iUsageIdx] = DISEM_FLAGS_GET( DISEM_FLAGS_S );
  2557. }
  2558. else
  2559. {
  2560. podf->pguid = &GUID_Unknown;
  2561. this->rgbaxissemflags[iUsageIdx] = DISEM_FLAGS_GET( DISEM_FLAGS_S );
  2562. }
  2563. /*
  2564. * Mark the primary axis associated with
  2565. * the matched axis as already set up.
  2566. */
  2567. this->rgiaxis[iUsageIdx] = uiObjPrimary;
  2568. this->df.rgodf[uiObjPrimary].dwType &= ~DIDFT_INSTANCEMASK;
  2569. this->df.rgodf[uiObjPrimary].dwType |= DIDFT_MAKEINSTANCE(iUsageIdx);
  2570. break;
  2571. }
  2572. }
  2573. }
  2574. else
  2575. {
  2576. /* Not an axis, with caps and input */
  2577. }
  2578. }
  2579. iCollection = 0;
  2580. iButton = 0;
  2581. iPOV = 0;
  2582. iAxis = 6;
  2583. for(uiObj = 0; uiObj < this->df.dwNumObjs; uiObj++)
  2584. {
  2585. PHIDUSAGEMAP phum;
  2586. PDWORD pdwType;
  2587. pdwType = &this->df.rgodf[uiObj].dwType;
  2588. if( !this->rghoc[uiObj].pcaps || this->rghoc[uiObj].pcaps->IsAlias
  2589. ||!( *pdwType & ( DIDFT_AXIS | DIDFT_BUTTON | DIDFT_POV | DIDFT_COLLECTION ) ))
  2590. {
  2591. continue;
  2592. }
  2593. if( *pdwType & DIDFT_COLLECTION )
  2594. {
  2595. *pdwType = (*pdwType & ~DIDFT_INSTANCEMASK) | DIDFT_MAKEINSTANCE(iCollection);
  2596. this->rgicoll[iCollection++] = uiObj;
  2597. continue;
  2598. }
  2599. else if( *pdwType & DIDFT_NODATA )
  2600. {
  2601. /*
  2602. * Leave other no data objects alone
  2603. */
  2604. continue;
  2605. }
  2606. if( *pdwType & DIDFT_BUTTON )
  2607. {
  2608. *pdwType &= ~DIDFT_INSTANCEMASK;
  2609. //The buttons need to be sorted (manbug 30320) --
  2610. //the ones that have USAGE_PAGE_BUTTON come first, sorted by button number,
  2611. //w/ gaps for missing numbers if necessary;
  2612. //then add on those that do not have USAGE_PAGE_BUTTON
  2613. //(since HID reports anything w/ size 1 bit is a button), unsorted.
  2614. if (this->rghoc[uiObj].pcaps->UsagePage == HID_USAGE_PAGE_BUTTON)
  2615. {
  2616. //put in the correct position, leaving gaps if needed.
  2617. //Usage - 1 will give us the position, since HID usages are 1-based,
  2618. //but DInput button indeces are 0-based.
  2619. int iPosition = ( this->rghoc[uiObj].pcaps->UsageMin
  2620. + uiObj
  2621. - this->rgdwBase[this->rghoc[uiObj].pcaps->type]
  2622. - this->rghoc[uiObj].pcaps->DataIndexMin ) - 1;
  2623. AssertF(iPosition >= 0);
  2624. *pdwType |= DIDFT_MAKEINSTANCE(iPosition);
  2625. this->rgiobj[iPosition] = uiObj;
  2626. }
  2627. else
  2628. {
  2629. //iLastIndex indicates where to put the non-USAGE_PAGE_BUTTON things
  2630. //in the order that they come in the report
  2631. *pdwType |= DIDFT_MAKEINSTANCE(iLastButtonIndex);
  2632. this->rgiobj[iLastButtonIndex++] = uiObj;
  2633. }
  2634. //increment the count of how many real things (excluing gaps) we've got
  2635. iButton++;
  2636. }
  2637. else if( *pdwType & DIDFT_AXIS )
  2638. {
  2639. if( piRemap[uiObj] == -1 )
  2640. {
  2641. WORD wUsage;
  2642. UINT uiObjPrimary = uiObj;
  2643. *pdwType &= ~DIDFT_INSTANCEMASK;
  2644. /*
  2645. * Check this axis and it's aliases for a match
  2646. */
  2647. while( TRUE )
  2648. {
  2649. wUsage = (WORD) ( this->rghoc[uiObj].pcaps->UsageMin
  2650. + uiObj
  2651. - this->rgdwBase[this->rghoc[uiObj].pcaps->type]
  2652. - this->rghoc[uiObj].pcaps->DataIndexMin );
  2653. phum = UsageToUsageMap( DIMAKEUSAGEDWORD(
  2654. this->rghoc[uiObj].pcaps->UsagePage, wUsage ) );
  2655. /*
  2656. * Slightly odd loop structure to avoid incrementing
  2657. * uiObj on the last iteration. This makes sure we
  2658. * don't miss anything in the outer loop and that
  2659. * uiObj relates to the alias we matched when testing
  2660. * for default semantic mappings.
  2661. */
  2662. if( phum || (uiObj+1 == this->df.dwNumObjs)
  2663. || !this->rghoc[uiObj+1].pcaps->IsAlias )
  2664. {
  2665. break;
  2666. }
  2667. uiObj++;
  2668. }
  2669. if( phum )
  2670. {
  2671. /*
  2672. * Since the axis is recognixed up the count
  2673. */
  2674. iTypeAxes++;
  2675. /*
  2676. * Find it's position keeping WinMM in mind.
  2677. */
  2678. if( ( phum->bPosAxis < 6 )
  2679. &&( this->rgiaxis[phum->bPosAxis] == -1 ) )
  2680. {
  2681. this->rgiaxis[phum->bPosAxis] = uiObjPrimary ;
  2682. *pdwType |= DIDFT_MAKEINSTANCE(phum->bPosAxis);
  2683. }
  2684. else if( ( phum->bPosAxis == 6 )
  2685. &&( this->rgiaxis[2] == -1 ) )
  2686. {
  2687. this->rgiaxis[2] = uiObjPrimary;
  2688. *pdwType |= DIDFT_MAKEINSTANCE(2);
  2689. }
  2690. else
  2691. {
  2692. *pdwType |= DIDFT_MAKEINSTANCE(iAxis);
  2693. this->rgiaxis[iAxis++] = uiObjPrimary ;
  2694. }
  2695. /*
  2696. * While we know which usage is most recognizable, add in
  2697. * flags to help us refine the device type and save off
  2698. * flags for default semantic mapping of this axis.
  2699. */
  2700. this->rgbaxissemflags[DIDFT_GETINSTANCE(*pdwType)] = phum->bSemFlag;
  2701. pdwHints[DIDFT_GETINSTANCE(*pdwType)] = phum->dwSemHint;
  2702. dwTypeFlags |= phum->dwSemHint;
  2703. }
  2704. else
  2705. {
  2706. /*
  2707. * Unfortunately, the current HID parser does not
  2708. * implement more unusual HID caps like "preferred
  2709. * state" so just assume any other axes are sliders.
  2710. */
  2711. if( this->rghoc[uiObj].pcaps->UsagePage == HID_USAGE_PAGE_SIMULATION )
  2712. {
  2713. if( wUsage == HID_USAGE_SIMULATION_CLUTCH )
  2714. {
  2715. dwTypeFlags |= DISEM_HINT_CLUTCH;
  2716. pdwHints[iAxis] = DISEM_HINT_CLUTCH;
  2717. this->rgbaxissemflags[iAxis] = DISEM_FLAGS_GET( DISEM_FLAGS_C );
  2718. iTypeAxes++;
  2719. }
  2720. else
  2721. {
  2722. if( wUsage == HID_USAGE_SIMULATION_SHIFTER )
  2723. {
  2724. dwTypeFlags |= DISEM_HINT_SHIFTER;
  2725. pdwHints[iAxis] = DISEM_HINT_CLUTCH;
  2726. iTypeAxes++;
  2727. }
  2728. else
  2729. {
  2730. pdwHints[iAxis] = DISEM_HINT_SLIDER;
  2731. }
  2732. this->rgbaxissemflags[iAxis] = DISEM_FLAGS_GET( DISEM_FLAGS_S );
  2733. }
  2734. }
  2735. *pdwType |= DIDFT_MAKEINSTANCE(iAxis);
  2736. this->rgiaxis[iAxis++] = uiObjPrimary ;
  2737. }
  2738. }
  2739. }
  2740. else
  2741. {
  2742. /*
  2743. * We already checked that it's one of the above or a POV
  2744. * so it must be a POV.
  2745. */
  2746. AssertF( *pdwType & DIDFT_POV );
  2747. *pdwType &= ~DIDFT_INSTANCEMASK;
  2748. *pdwType |= DIDFT_MAKEINSTANCE(iPOV);
  2749. this->rgipov[iPOV++] = uiObj;
  2750. dwTypeFlags |= DISEM_HINT_POV;
  2751. }
  2752. }
  2753. /*
  2754. * Now that we know about all the controls we base our type
  2755. * decisions on, setup/validate the type and subtype.
  2756. */
  2757. AssertF( GET_DIDEVICE_TYPE( this->dwDevType ) != DI8DEVTYPE_KEYBOARD );
  2758. if( GET_DIDEVICE_TYPE( this->dwDevType ) == DI8DEVTYPE_MOUSE )
  2759. {
  2760. if( dwTypeFlags & DISEM_HINT_ABSOLUTE )
  2761. {
  2762. this->dwDevType = MAKE_DIDEVICE_TYPE(DI8DEVTYPE_MOUSE,
  2763. DI8DEVTYPEMOUSE_ABSOLUTE)
  2764. | DIDEVTYPE_HID;
  2765. }
  2766. }
  2767. else
  2768. {
  2769. DWORD dwFlags2;
  2770. JOYREGHWSETTINGS hws;
  2771. /*
  2772. * Get the old registry flags for initial hints in case this
  2773. * device has more generic usages than it needed to have and
  2774. * these have registry overrides.
  2775. * Only look for flags that are less generic to avoid a case
  2776. * where an older DInput (or JoyHID) labelled this device
  2777. * inadequately.
  2778. * If the call fails the buffer is zeroed
  2779. */
  2780. JoyReg_GetValue(this->hkType, REGSTR_VAL_JOYOEMDATA,
  2781. REG_BINARY, &hws, cbX(hws));
  2782. if( this->hkProp )
  2783. {
  2784. JoyReg_GetValue( this->hkProp, REGSTR_VAL_FLAGS2, REG_BINARY,
  2785. &dwFlags2, cbX(dwFlags2) );
  2786. }
  2787. CAssertF( ( DISEM_HINT_THROTTLE >> 6 ) == JOY_HWS_HASZ );
  2788. CAssertF( ( DISEM_HINT_POV >> 6 ) == JOY_HWS_HASPOV );
  2789. dwTestType = GetValidDI8DevType( dwFlags2, iButton, dwTypeFlags >> 14 );
  2790. if( dwTestType )
  2791. {
  2792. /*
  2793. * If a valid override exists just use it
  2794. */
  2795. this->dwDevType = dwTestType | DIDEVTYPE_HID;
  2796. }
  2797. else
  2798. {
  2799. #ifdef XDEBUG
  2800. /*
  2801. * Fetch the value again in debug so we can report failures.
  2802. */
  2803. if( this->hkProp )
  2804. {
  2805. DWORD dwDbgFlags2;
  2806. JoyReg_GetValue( this->hkProp, REGSTR_VAL_FLAGS2, REG_BINARY,
  2807. &dwDbgFlags2, cbX(dwDbgFlags2) );
  2808. if( GET_DIDEVICE_TYPEANDSUBTYPE( dwDbgFlags2 ) )
  2809. {
  2810. RPF( "Ignoring invalid type/subtype Flags2 value 0x%08x for HID", dwDbgFlags2 );
  2811. }
  2812. }
  2813. #endif
  2814. /*
  2815. * This one is straight forward
  2816. */
  2817. if( hws.dwFlags & JOY_HWS_ISHEADTRACKER )
  2818. {
  2819. dwTestType = MAKE_DIDEVICE_TYPE(DI8DEVTYPE_SUPPLEMENTAL,
  2820. DI8DEVTYPESUPPLEMENTAL_HEADTRACKER );
  2821. goto MNK_CheckType;
  2822. }
  2823. if( hws.dwFlags & JOY_HWS_ISYOKE )
  2824. {
  2825. dwTestType = MAKE_DIDEVICE_TYPE(DI8DEVTYPE_FLIGHT,
  2826. DI8DEVTYPEFLIGHT_YOKE);
  2827. goto MNK_CheckType;
  2828. }
  2829. /*
  2830. * Other registry flags only relate to the type so the
  2831. * subtype will still need to be found.
  2832. */
  2833. if( hws.dwFlags & JOY_HWS_ISGAMEPAD )
  2834. {
  2835. dwTestType = MAKE_DIDEVICE_TYPE(DI8DEVTYPE_GAMEPAD, DI8DEVTYPEGAMEPAD_STANDARD);
  2836. goto MNK_AdjustType;
  2837. }
  2838. }
  2839. /*
  2840. * If we have somehow recognized this as a car controller, do any
  2841. * processing necessary to munge the axes.
  2842. * Note we have to go through this path, even if the device has a
  2843. * registry override type and subtype so that the right axes get
  2844. * used for a device which has been changed into a car controller
  2845. */
  2846. if( ( hws.dwFlags & JOY_HWS_ISCARCTRL )
  2847. || fCarController
  2848. || ( GET_DIDEVICE_TYPE( this->dwDevType ) == DI8DEVTYPE_DRIVING ) )
  2849. {
  2850. dwTestType = MAKE_DIDEVICE_TYPE(DI8DEVTYPE_DRIVING, 0);
  2851. if( DISEM_HINT_X == ( dwTypeFlags & ( DISEM_HINT_X | DISEM_HINT_STEERING ) ) )
  2852. {
  2853. /*
  2854. * If the device has no wheel but has an X axis
  2855. * use that instead. The semantic flags are the
  2856. * same so just switch the hints.
  2857. */
  2858. dwTypeFlags ^= ( DISEM_HINT_X | DISEM_HINT_STEERING );
  2859. }
  2860. if( ( dwTypeFlags & DISEM_HINT_STEERING ) == 0 )
  2861. {
  2862. /*
  2863. * If there's still no steering wheel, make the type
  2864. * device so it can be processed into a supplemental
  2865. */
  2866. dwTestType = MAKE_DIDEVICE_TYPE( DI8DEVTYPE_DEVICE, 0 );
  2867. }
  2868. /*
  2869. * In terms of HID usages, the common forms of pedals are:
  2870. *
  2871. * 1) Accellerator and Brake
  2872. * 2) Split Y axis, below center accel, above brake
  2873. * 3) Z accel, Y brake
  2874. * 4) Y accel, Rz brake
  2875. * 5) Z accel, Rz brake
  2876. *
  2877. * The first form is ideal so all that is needed is to
  2878. * make sure that any further processing does not disturb
  2879. * those axes whilst allowing for only one being exact.
  2880. * The second form is assumed for a car controller with
  2881. * only a Y (in addition to a possible X).
  2882. * The other two forms are distinguished either by an
  2883. * explicite registry flag or by the exact match of Y and
  2884. * Rz with none of Z, accel or brake for the latter form.
  2885. * Since a real Z axis would be an oddity on a steering
  2886. * wheel, assume that the IHVs who have taken the Y, Rz
  2887. * path are not going to add a Z.
  2888. */
  2889. /*
  2890. * If there is an override to Y split pedals and a Y is
  2891. * present then set type and subtype and bypass the rest.
  2892. */
  2893. switch( dwFlags2 & JOYTYPE_INFOMASK )
  2894. {
  2895. case JOYTYPE_INFODEFAULT:
  2896. break;
  2897. case JOYTYPE_INFOYYPEDALS:
  2898. if( dwTypeFlags & DISEM_HINT_Y )
  2899. {
  2900. if( dwTypeFlags & DISEM_HINT_STEERING )
  2901. {
  2902. dwTestType = MAKE_DIDEVICE_TYPE( DI8DEVTYPE_DRIVING, DI8DEVTYPEDRIVING_COMBINEDPEDALS );
  2903. }
  2904. else
  2905. {
  2906. AssertF( GET_DIDEVICE_TYPEANDSUBTYPE( dwTestType ) == MAKE_DIDEVICE_TYPE( DI8DEVTYPE_DEVICE, 0 ) );
  2907. }
  2908. goto MNK_CheckType;
  2909. }
  2910. RPF( "JOYTYPE_INFOYYPEDALS set but device has no Y" );
  2911. break;
  2912. case JOYTYPE_INFOZYPEDALS:
  2913. ReinterpretObject( this, pdwHints, cAxes, &dwTypeFlags,
  2914. DISEM_HINT_Y, DISEM_HINT_BRAKE,
  2915. DISEM_FLAGS_GET(DIAXIS_ANY_B_1), &GUID_RzAxis );
  2916. ReinterpretObject( this, pdwHints, cAxes, &dwTypeFlags,
  2917. DISEM_HINT_Z, DISEM_HINT_ACCELERATOR,
  2918. DISEM_FLAGS_GET(DIAXIS_ANY_A_1), &GUID_YAxis );
  2919. ReinterpretObject( this, pdwHints, cAxes, &dwTypeFlags,
  2920. DISEM_HINT_THROTTLE, DISEM_HINT_ACCELERATOR,
  2921. DISEM_FLAGS_GET(DIAXIS_ANY_A_1), &GUID_YAxis );
  2922. break;
  2923. case JOYTYPE_INFOYRPEDALS:
  2924. ReinterpretObject( this, pdwHints, cAxes, &dwTypeFlags,
  2925. DISEM_HINT_RZ, DISEM_HINT_BRAKE,
  2926. DISEM_FLAGS_GET(DIAXIS_ANY_B_1), &GUID_RzAxis );
  2927. ReinterpretObject( this, pdwHints, cAxes, &dwTypeFlags,
  2928. DISEM_HINT_Y, DISEM_HINT_ACCELERATOR,
  2929. DISEM_FLAGS_GET(DIAXIS_ANY_A_1), &GUID_YAxis );
  2930. break;
  2931. case JOYTYPE_INFOZRPEDALS:
  2932. ReinterpretObject( this, pdwHints, cAxes, &dwTypeFlags,
  2933. DISEM_HINT_RZ, DISEM_HINT_BRAKE,
  2934. DISEM_FLAGS_GET(DIAXIS_ANY_B_1), &GUID_RzAxis );
  2935. ReinterpretObject( this, pdwHints, cAxes, &dwTypeFlags,
  2936. DISEM_HINT_Z, DISEM_HINT_ACCELERATOR,
  2937. DISEM_FLAGS_GET(DIAXIS_ANY_A_1), &GUID_YAxis );
  2938. ReinterpretObject( this, pdwHints, cAxes, &dwTypeFlags,
  2939. DISEM_HINT_THROTTLE, DISEM_HINT_ACCELERATOR,
  2940. DISEM_FLAGS_GET(DIAXIS_ANY_A_1), &GUID_YAxis );
  2941. break;
  2942. default:
  2943. RPF( "Ignoring invalid JOYTYPE_INFO* Flags in 0x%08x", dwFlags2 & JOYTYPE_INFOMASK );
  2944. }
  2945. /*
  2946. * In the absence of an override, first see if there's
  2947. * anything worth reinterpreting.
  2948. */
  2949. if( 0 == ( dwTypeFlags &
  2950. ( DISEM_HINT_Z | DISEM_HINT_ACCELERATOR | DISEM_HINT_THROTTLE
  2951. | DISEM_HINT_RZ | DISEM_HINT_BRAKE | DISEM_HINT_ACCELERATOR ) ) )
  2952. {
  2953. if( ( dwTypeFlags & ( DISEM_HINT_STEERING | DISEM_HINT_Y ) )
  2954. == ( DISEM_HINT_STEERING | DISEM_HINT_Y ) )
  2955. {
  2956. /*
  2957. * Combined pedal device
  2958. */
  2959. dwTestType = MAKE_DIDEVICE_TYPE( DI8DEVTYPE_DRIVING, DI8DEVTYPEDRIVING_COMBINEDPEDALS );
  2960. }
  2961. else
  2962. {
  2963. AssertF( GET_DIDEVICE_TYPEANDSUBTYPE( dwTestType ) == MAKE_DIDEVICE_TYPE( DI8DEVTYPE_DEVICE, 0 ) );
  2964. }
  2965. goto MNK_CheckType;
  2966. }
  2967. else if( ( DISEM_HINT_Y | DISEM_HINT_RZ ) ==
  2968. ( dwTypeFlags
  2969. & ( DISEM_HINT_Y | DISEM_HINT_Z | DISEM_HINT_RZ | DISEM_HINT_BRAKE | DISEM_HINT_ACCELERATOR ) ) )
  2970. {
  2971. /*
  2972. * Although the axis GUIDs accel == Y and brake == RZ are
  2973. * already correct, use the common function to change the
  2974. * semantic flags or I'll forget to change the axis flags.
  2975. */
  2976. ReinterpretObject( this, pdwHints, cAxes, &dwTypeFlags,
  2977. DISEM_HINT_Y, DISEM_HINT_ACCELERATOR,
  2978. DISEM_FLAGS_GET(DIAXIS_ANY_A_1), &GUID_YAxis );
  2979. ReinterpretObject( this, pdwHints, cAxes, &dwTypeFlags,
  2980. DISEM_HINT_RZ, DISEM_HINT_BRAKE,
  2981. DISEM_FLAGS_GET(DIAXIS_ANY_B_1), &GUID_RzAxis );
  2982. }
  2983. else
  2984. {
  2985. /*
  2986. * Both of the other split pedal types have a Z-like accelerator
  2987. */
  2988. ReinterpretObject( this, pdwHints, cAxes, &dwTypeFlags,
  2989. DISEM_HINT_Z, DISEM_HINT_ACCELERATOR,
  2990. DISEM_FLAGS_GET(DIAXIS_ANY_A_1), &GUID_YAxis );
  2991. ReinterpretObject( this, pdwHints, cAxes, &dwTypeFlags,
  2992. DISEM_HINT_THROTTLE, DISEM_HINT_ACCELERATOR,
  2993. DISEM_FLAGS_GET(DIAXIS_ANY_A_1), &GUID_YAxis );
  2994. /*
  2995. * Look for a brake on RZ before Y as a device with RZ
  2996. * is very likely to report a Y as well.
  2997. */
  2998. ReinterpretObject( this, pdwHints, cAxes, &dwTypeFlags,
  2999. DISEM_HINT_RZ, DISEM_HINT_BRAKE,
  3000. DISEM_FLAGS_GET(DIAXIS_ANY_B_1), &GUID_RzAxis );
  3001. ReinterpretObject( this, pdwHints, cAxes, &dwTypeFlags,
  3002. DISEM_HINT_Y, DISEM_HINT_BRAKE,
  3003. DISEM_FLAGS_GET(DIAXIS_ANY_B_1), &GUID_RzAxis );
  3004. }
  3005. /*
  3006. * If somehow we have found an accellerator, make sure we
  3007. * don't expose any Y axes as well or the accellerator
  3008. * may get bumped from the default Y position.
  3009. */
  3010. if( dwTypeFlags & DISEM_HINT_ACCELERATOR )
  3011. {
  3012. int idx;
  3013. dwTypeFlags &= ~DISEM_HINT_Y;
  3014. for( idx = 0; idx < cAxes + 6; idx++ )
  3015. {
  3016. if( pdwHints[idx] == DISEM_HINT_Y )
  3017. {
  3018. pdwHints[idx] = DISEM_HINT_SLIDER;
  3019. dwTypeFlags |= DISEM_HINT_SLIDER;
  3020. this->rgbaxissemflags[idx] = DISEM_FLAGS_GET(DIAXIS_ANY_S_1);
  3021. this->df.rgodf[this->rgiaxis[idx]].pguid = &GUID_Slider;
  3022. }
  3023. }
  3024. }
  3025. }
  3026. else
  3027. {
  3028. /*
  3029. * Just take the default calculated from the HID caps (or the override)
  3030. */
  3031. dwTestType = this->dwDevType;
  3032. #ifdef XDEBUG
  3033. if( GET_DIDEVICE_TYPEANDSUBTYPE( dwTestType ) != GET_DIDEVICE_TYPEANDSUBTYPE( dwFlags2 ) )
  3034. {
  3035. switch( GET_DIDEVICE_TYPE( dwTestType ) )
  3036. {
  3037. case DI8DEVTYPE_DEVICE:
  3038. AssertF( GET_DIDEVICE_SUBTYPE( dwTestType ) == 0 );
  3039. break;
  3040. case DI8DEVTYPE_JOYSTICK:
  3041. AssertF( GET_DIDEVICE_SUBTYPE( dwTestType ) == DI8DEVTYPEJOYSTICK_STANDARD );
  3042. break;
  3043. case DI8DEVTYPE_GAMEPAD:
  3044. AssertF( GET_DIDEVICE_SUBTYPE( dwTestType ) == DI8DEVTYPEGAMEPAD_STANDARD );
  3045. break;
  3046. default:
  3047. RPF( "Invalid type %02x", GET_DIDEVICE_TYPE( dwTestType ) );
  3048. AssertF( !"Invalid type!" );
  3049. }
  3050. }
  3051. #endif
  3052. /*
  3053. * Check for Z axis behavior overrides
  3054. * Since the default behavior is to always use a Z as a Z,
  3055. * only the override to slider is needed here.
  3056. */
  3057. if( dwFlags2 & JOYTYPE_INFOZISSLIDER )
  3058. {
  3059. if( dwTypeFlags & DISEM_HINT_Z )
  3060. {
  3061. /*
  3062. * Reset the slider flag as ReinterpretObject does
  3063. * not change axes if the target this axis
  3064. */
  3065. dwTypeFlags &= ~DISEM_HINT_SLIDER;
  3066. ReinterpretObject( this, pdwHints, cAxes, &dwTypeFlags,
  3067. DISEM_HINT_Z, DISEM_HINT_SLIDER,
  3068. DISEM_FLAGS_GET(DIAXIS_ANY_S_1), &GUID_Slider );
  3069. }
  3070. else
  3071. {
  3072. RPF( "JOYTYPE_INFOZISSLIDER set but device has no Z" );
  3073. }
  3074. }
  3075. }
  3076. /*
  3077. * If the dwFlags2 and dwTestType are the same, we are using a
  3078. * registry override so don't try to refine it.
  3079. */
  3080. if( GET_DIDEVICE_TYPEANDSUBTYPE( dwTestType ) != GET_DIDEVICE_TYPEANDSUBTYPE( dwFlags2 ) )
  3081. {
  3082. if( dwTypeFlags & DISEM_HINT_STEERING )
  3083. {
  3084. /*
  3085. * If it has a steering wheel, it's a driving device
  3086. */
  3087. dwTestType = MAKE_DIDEVICE_TYPE(DI8DEVTYPE_DRIVING, 0 );
  3088. }
  3089. else if( ( dwTypeFlags & DISEM_HINT_SIXDOF ) == DISEM_HINT_SIXDOF )
  3090. {
  3091. /*
  3092. * Special case six degree of freedom devices
  3093. */
  3094. dwTestType = MAKE_DIDEVICE_TYPE(DI8DEVTYPE_1STPERSON,
  3095. DI8DEVTYPE1STPERSON_SIXDOF );
  3096. goto MNK_CheckType;
  3097. }
  3098. MNK_AdjustType:;
  3099. /*
  3100. * We should be left with only the following device types:
  3101. * joystick, gamepad, driving and device
  3102. * For the first three only subtypes need to be found.
  3103. * For DI8DEVTYPE_DEVICE some may be changed to
  3104. * DI8DEVTYPE_SUPPLEMENTAL if an appropriate subtype can be
  3105. * found.
  3106. */
  3107. switch( GET_DIDEVICE_TYPE( dwTestType ) )
  3108. {
  3109. case DI8DEVTYPE_DEVICE:
  3110. /*
  3111. * Since this is not a joystick or gamepad, only use it
  3112. * if it has the vehicle simulation controls we support.
  3113. */
  3114. if( ( dwTypeFlags & ( DISEM_HINT_ACCELERATOR | DISEM_HINT_BRAKE | DISEM_HINT_CLUTCH ) )
  3115. == ( DISEM_HINT_ACCELERATOR | DISEM_HINT_BRAKE | DISEM_HINT_CLUTCH ) )
  3116. {
  3117. dwTestType = MAKE_DIDEVICE_TYPE( DI8DEVTYPE_SUPPLEMENTAL,
  3118. DI8DEVTYPESUPPLEMENTAL_THREEPEDALS );
  3119. }
  3120. else if( ( dwTypeFlags & ( DISEM_HINT_ACCELERATOR | DISEM_HINT_BRAKE ) )
  3121. == ( DISEM_HINT_ACCELERATOR | DISEM_HINT_BRAKE ) )
  3122. {
  3123. dwTestType = MAKE_DIDEVICE_TYPE( DI8DEVTYPE_SUPPLEMENTAL,
  3124. DI8DEVTYPESUPPLEMENTAL_DUALPEDALS );
  3125. }
  3126. else if( dwTypeFlags & DISEM_HINT_THROTTLE )
  3127. {
  3128. dwTestType = MAKE_DIDEVICE_TYPE( DI8DEVTYPE_SUPPLEMENTAL,
  3129. DI8DEVTYPESUPPLEMENTAL_THROTTLE );
  3130. }
  3131. else if( dwTypeFlags & DISEM_HINT_SHIFTER )
  3132. {
  3133. dwTestType = MAKE_DIDEVICE_TYPE( DI8DEVTYPE_SUPPLEMENTAL,
  3134. DI8DEVTYPESUPPLEMENTAL_SHIFTER );
  3135. }
  3136. else if( dwTypeFlags & DISEM_HINT_RUDDER )
  3137. {
  3138. dwTestType = MAKE_DIDEVICE_TYPE( DI8DEVTYPE_SUPPLEMENTAL,
  3139. DI8DEVTYPESUPPLEMENTAL_RUDDERPEDALS );
  3140. }
  3141. else
  3142. {
  3143. /*
  3144. * Totally unknown so leave it as device
  3145. * Allowing other devices to be treated as game
  3146. * controllers can cause HID controls on devices
  3147. * such as speakers to be included.
  3148. */
  3149. }
  3150. break;
  3151. case DI8DEVTYPE_JOYSTICK:
  3152. case DI8DEVTYPE_GAMEPAD:
  3153. if( ( dwTypeFlags & ( DISEM_HINT_X | DISEM_HINT_Y ) ) != ( DISEM_HINT_X | DISEM_HINT_Y ) )
  3154. {
  3155. dwTestType = MAKE_DIDEVICE_TYPE( DI8DEVTYPE_SUPPLEMENTAL,
  3156. DI8DEVTYPESUPPLEMENTAL_UNKNOWN );
  3157. }
  3158. break;
  3159. case DI8DEVTYPE_DRIVING:
  3160. if( ( dwTypeFlags & ( DISEM_HINT_ACCELERATOR | DISEM_HINT_BRAKE | DISEM_HINT_CLUTCH ) )
  3161. == ( DISEM_HINT_ACCELERATOR | DISEM_HINT_BRAKE | DISEM_HINT_CLUTCH ) )
  3162. {
  3163. dwTestType |= MAKE_DIDEVICE_TYPE( 0, DI8DEVTYPEDRIVING_THREEPEDALS );
  3164. }
  3165. else if( ( dwTypeFlags & ( DISEM_HINT_ACCELERATOR | DISEM_HINT_BRAKE ) )
  3166. == ( DISEM_HINT_ACCELERATOR | DISEM_HINT_BRAKE ) )
  3167. {
  3168. dwTestType |= MAKE_DIDEVICE_TYPE( 0, DI8DEVTYPEDRIVING_DUALPEDALS );
  3169. }
  3170. else if( dwTypeFlags & DISEM_HINT_Y )
  3171. {
  3172. dwTestType |= MAKE_DIDEVICE_TYPE( 0, DI8DEVTYPEDRIVING_COMBINEDPEDALS );
  3173. }
  3174. else
  3175. {
  3176. dwTestType |= MAKE_DIDEVICE_TYPE( 0, DI8DEVTYPEDRIVING_LIMITED );
  3177. }
  3178. break;
  3179. default:
  3180. AssertF( !"Unexpected device type" );
  3181. }
  3182. /*
  3183. * Use the common function to make this a limited type if the
  3184. * number of buttons or flags dictate it.
  3185. * Since the type and subtype are known to be valid, the return
  3186. * value should never be a failure (zero).
  3187. */
  3188. MNK_CheckType:;
  3189. this->dwDevType = DIDEVTYPE_HID
  3190. | GetValidDI8DevType( dwTestType, iButton, hws.dwFlags );
  3191. AssertF( this->dwDevType & ~DIDEVTYPE_HID );
  3192. }
  3193. }
  3194. /*
  3195. * Finally, mark all secondary aliases with the primary alias
  3196. * instance and sqfl all the translations.
  3197. */
  3198. for(uiObj = 0; uiObj < this->df.dwNumObjs; uiObj++)
  3199. {
  3200. int iPrimary;
  3201. D( iPrimary = -1; )
  3202. if( this->rghoc[uiObj].pcaps )
  3203. {
  3204. if( !this->rghoc[uiObj].pcaps->IsAlias )
  3205. {
  3206. iPrimary = this->df.rgodf[uiObj].dwType;
  3207. }
  3208. else
  3209. {
  3210. D( AssertF( iPrimary != -1 ) );
  3211. /*
  3212. * Prefix notices that iPrimary would be uninitialized if
  3213. * we find the alias before the primary but that should
  3214. * never happen as the object are sorted by definition.
  3215. */
  3216. if( DIDFT_GETTYPE(iPrimary) != DIDFT_GETTYPE(this->df.rgodf[uiObj].dwType) )
  3217. {
  3218. SquirtSqflPtszV(sqflHidParse | sqflError,
  3219. TEXT("CHid_MungeNotKeyboard: uiObj: %d dwType 0x%08x ")
  3220. TEXT("does not match primary 0x%08x"),
  3221. uiObj, this->df.rgodf[uiObj].dwType, iPrimary );
  3222. }
  3223. /*
  3224. * There are very few attributes of an alias that are not
  3225. * overridden by the primary.
  3226. */
  3227. this->df.rgodf[uiObj].dwType = ( iPrimary & ~DIDFT_ALIASATTRMASK )
  3228. | ( this->df.rgodf[uiObj].dwType & DIDFT_ALIASATTRMASK );
  3229. }
  3230. SquirtSqflPtszV(sqflHidParse | sqflVerbose,
  3231. TEXT("CHid_MungeNotKeyboard: uiObj: %d set to dwType 0x%08x"),
  3232. uiObj, this->df.rgodf[uiObj].dwType );
  3233. }
  3234. else
  3235. {
  3236. SquirtSqflPtszV(sqflHidParse | sqflVerbose,
  3237. TEXT("CHid_MungeNotKeyboard: uiObj: %d has pcaps == NULL"),
  3238. uiObj );
  3239. }
  3240. }
  3241. }
  3242. else
  3243. {
  3244. FreePpv( &this->rgbaxissemflags );
  3245. }
  3246. FreePpv( &piRemap );
  3247. return hres;
  3248. }
  3249. /*****************************************************************************
  3250. *
  3251. * @doc INTERNAL
  3252. *
  3253. * @method HRESULT | CHid | InitObjects |
  3254. *
  3255. * Identify and initialize the objects supported by the device.
  3256. *
  3257. *****************************************************************************/
  3258. HRESULT INTERNAL
  3259. CHid_InitObjects(PCHID this)
  3260. {
  3261. HRESULT hres;
  3262. UINT uiObj;
  3263. UINT iType;
  3264. /*
  3265. * Build the base array table to convert HID item indexes
  3266. * into DirectInput ID instance numbers.
  3267. */
  3268. AssertF(this->rgdwBase[HidP_Input] == 0);
  3269. this->rgdwBase[HidP_Feature] = this->caps.NumberInputDataIndices;
  3270. this->rgdwBase[HidP_Output ] = this->rgdwBase[HidP_Feature] +
  3271. this->caps.NumberFeatureDataIndices;
  3272. this->rgdwBase[HidP_Coll ] = this->rgdwBase[HidP_Output ] +
  3273. this->caps.NumberOutputDataIndices;
  3274. /*
  3275. * Determine if this device supports PID
  3276. */
  3277. this->fPIDdevice = FALSE;
  3278. if( this->caps.NumberOutputValueCaps != 0x0
  3279. && this->caps.NumberOutputButtonCaps != 0x0 )
  3280. {
  3281. NTSTATUS ntStat;
  3282. USHORT cAButton=0x0;
  3283. ntStat = HidP_GetSpecificButtonCaps
  3284. (
  3285. HidP_Output, // ReportType
  3286. HID_USAGE_PAGE_PID, // UsagePage
  3287. 0x0, // Link Collection
  3288. 0x0, // Usage
  3289. NULL, // ValueCaps
  3290. &cAButton, // ValueCapsLength
  3291. this->ppd // PreparsedData
  3292. );
  3293. if( ntStat == HIDP_STATUS_BUFFER_TOO_SMALL
  3294. && cAButton > 0x2 // Is this enough for PID device ??
  3295. )
  3296. {
  3297. this->fPIDdevice = TRUE;
  3298. }
  3299. }
  3300. /*
  3301. * Note that we must do axes first because that keeps
  3302. * everything aligned.
  3303. *
  3304. * Warning, diem.c assumes axes come first.
  3305. */
  3306. hres = CHid_InitAxes(this);
  3307. if(FAILED(hres))
  3308. {
  3309. goto done;
  3310. }
  3311. hres = CHid_InitButtons(this);
  3312. if(FAILED(hres))
  3313. {
  3314. goto done;
  3315. }
  3316. hres = CHid_InitCollections(this);
  3317. if(FAILED(hres))
  3318. {
  3319. goto done;
  3320. }
  3321. /*
  3322. * Round the data size up to the nearest DWORD.
  3323. */
  3324. this->df.dwDataSize = (this->df.dwDataSize + 3) & ~3;
  3325. /*
  3326. * Allocate memory for report ID enable flags
  3327. *
  3328. * ISSUE-2001/05/12-MarcAnd Memory allocations should be merged
  3329. * These memory blocks could be merged. For most devices the total memory
  3330. * needed is only one or two bytes so there may be better ways.
  3331. */
  3332. for( iType = HidP_Input; iType < HidP_Max; iType++ )
  3333. {
  3334. this->wMaxReportId[iType] += 1;
  3335. hres = AllocCbPpv(this->wMaxReportId[iType], &this->pEnableReportId[iType]);
  3336. if( FAILED(hres) )
  3337. {
  3338. goto done;
  3339. }
  3340. }
  3341. AssertF(this->rgiobj == 0);
  3342. /*
  3343. * Munge the data before trying to look up supplemental
  3344. * information in the registry.
  3345. */
  3346. if(GET_DIDEVICE_TYPE(this->dwDevType) == DI8DEVTYPE_KEYBOARD)
  3347. {
  3348. CHid_MungeKeyboard(this);
  3349. }
  3350. else
  3351. {
  3352. CHid_MungeNotKeyboard(this);
  3353. }
  3354. /*
  3355. * Collect attributes for each object and add them to the
  3356. * device type code. This allows the registry to enable
  3357. * things like force feedback.
  3358. */
  3359. for(uiObj = 0; uiObj < this->df.dwNumObjs; uiObj++)
  3360. {
  3361. CType_RegGetTypeInfo(this->hkType, &this->df.rgodf[uiObj], this->fPIDdevice);
  3362. if( ( GET_DIDEVICE_TYPE(this->dwDevType) == DI8DEVTYPE_DRIVING )
  3363. && ( this->df.rgodf[uiObj].dwFlags & DIDOI_FFACTUATOR )
  3364. && ( this->df.rgodf[uiObj].pguid != &GUID_XAxis ) )
  3365. {
  3366. /*
  3367. * IHVs set FF attributes on non-FF axes for wheels because
  3368. * first generation FF apps were only written to support joysticks.
  3369. * Since we now munge the various configurations of pedal axes to
  3370. * report all split pedals in the same way, the fake Y axis can
  3371. * land up on different axes, usually Slider0. Rather than have
  3372. * people code to these different fake axes, strip out actuator
  3373. * status from any driving axis except the wheel.
  3374. */
  3375. this->df.rgodf[uiObj].dwFlags &= ~DIDOI_FFACTUATOR;
  3376. this->df.rgodf[uiObj].dwType &= ~DIDFT_FFACTUATOR;
  3377. }
  3378. }
  3379. #ifdef DEBUG
  3380. for(uiObj = 0; uiObj < this->df.dwNumObjs; uiObj++)
  3381. {
  3382. PHIDGROUPCAPS pcaps;
  3383. UINT uiObjReal =
  3384. CHid_ObjFromType(this, this->df.rgodf[uiObj].dwType);
  3385. pcaps = this->rghoc[uiObjReal].pcaps;
  3386. if(pcaps)
  3387. {
  3388. AssertF(pcaps->dwSignature == HIDGROUPCAPS_SIGNATURE);
  3389. }
  3390. if( uiObjReal != uiObj )
  3391. {
  3392. RPF( "uiObj = 0x%08x, type = 0x%08x, exposed Obj = 0x%08x",
  3393. uiObj, this->df.rgodf[uiObj].dwType, uiObjReal );
  3394. }
  3395. AssertF(CHid_ObjFromType(this, this->df.rgodf[uiObj].dwType)
  3396. == uiObj);
  3397. /*
  3398. * Anything that is DIDFT_AXIS must be a HID axis. However,
  3399. * the converse is not true for the case of analog buttons.
  3400. */
  3401. AssertF(fLimpFF(this->df.rgodf[uiObj].dwType & DIDFT_AXIS,
  3402. pcaps->IsValue));
  3403. SquirtSqflPtszV(sqfl | sqflVerbose,
  3404. TEXT("CHid_InitObj: uiObj = %02x, dwType = %08x"),
  3405. uiObj, this->df.rgodf[uiObj].dwType);
  3406. }
  3407. #endif
  3408. hres = S_OK;
  3409. done:;
  3410. return hres;
  3411. }
  3412. /*****************************************************************************
  3413. *
  3414. * @doc INTERNAL
  3415. *
  3416. * @method HRESULT | CHid | InitParse |
  3417. *
  3418. * Identify and initialize the data structures needed for
  3419. * parsing reports.
  3420. *
  3421. *****************************************************************************/
  3422. HRESULT INTERNAL
  3423. CHid_InitParse(PCHID this)
  3424. {
  3425. DWORD cb;
  3426. HRESULT hres;
  3427. /*
  3428. * Obtain the maximum number of HIDP_DATA structures
  3429. * that will be returned at one go.
  3430. */
  3431. this->hriIn .cdataMax = HidP_MaxDataListLength(HidP_Input , this->ppd);
  3432. this->hriOut.cdataMax = HidP_MaxDataListLength(HidP_Output, this->ppd);
  3433. this->hriFea.cdataMax = HidP_MaxDataListLength(HidP_Feature, this->ppd);
  3434. /*
  3435. * More annoyances.
  3436. */
  3437. this->hriIn .cbReport = this->caps. InputReportByteLength;
  3438. this->hriOut.cbReport = this->caps. OutputReportByteLength;
  3439. this->hriFea.cbReport = this->caps.FeatureReportByteLength;
  3440. /*
  3441. * Some trace squirties because HID is tricky.
  3442. */
  3443. SquirtSqflPtszV(sqflHidParse,
  3444. TEXT("CHid_InitParse: MaxDataListLength(Input) = %d"),
  3445. this->hriIn.cdataMax);
  3446. SquirtSqflPtszV(sqflHidParse,
  3447. TEXT("CHid_InitParse: MaxDataListLength(Output) = %d"),
  3448. this->hriOut.cdataMax);
  3449. SquirtSqflPtszV(sqflHidParse,
  3450. TEXT("CHid_InitParse: MaxDataListLength(Feature)= %d"),
  3451. this->hriFea.cdataMax);
  3452. SquirtSqflPtszV(sqflHidParse,
  3453. TEXT("CHid_InitParse: InputReportByteLength = %d"),
  3454. this->caps.InputReportByteLength);
  3455. SquirtSqflPtszV(sqflHidParse,
  3456. TEXT("CHid_InitParse: OutputReportByteLength = %d"),
  3457. this->caps.OutputReportByteLength);
  3458. SquirtSqflPtszV(sqflHidParse,
  3459. TEXT("CHid_InitParse: FeatureReportByteLength = %d"),
  3460. this->caps.FeatureReportByteLength);
  3461. /*
  3462. * Now allocate all the report-related memory.
  3463. */
  3464. this->cbPhys = this->df.dwDataSize;
  3465. /*
  3466. * Allocating the memory is done in four phases.
  3467. *
  3468. * 1. Tally up how much memory we need,
  3469. * 2. Allocate that memory,
  3470. * 3. Dole out the memory we allocated,
  3471. * 4. Check that we didn't mess up.
  3472. *
  3473. * Since this is extremely error-prone (I've messed it up at least
  3474. * once), the work is hidden inside macros.
  3475. *
  3476. * The macro THINGS expands to a series of THING()s, each of which
  3477. * specifies a field name and the size it should be. Each time you
  3478. * want to iterate over the fields, use the THINGS macro.
  3479. *
  3480. * (Yes, this is the same comment block as when we did this before.)
  3481. *
  3482. * Note, the arrays of HIDP_DATA structures must be correctly
  3483. * aligned in some architechtures.
  3484. */
  3485. CAssertF( FIELD_OFFSET(CHID, hriIn.rgdata) == FIELD_OFFSET(CHID, pvGroup2) );
  3486. #define THINGS() \
  3487. THING(hriIn.rgdata, cbCxX(this->hriIn.cdataMax, HIDP_DATA)); \
  3488. THING(hriOut.rgdata, cbCxX(this->hriOut.cdataMax, HIDP_DATA)); \
  3489. THING(hriFea.rgdata, cbCxX(this->hriFea.cdataMax, HIDP_DATA)); \
  3490. THING(hriIn.pvReport, this->hriIn.cbReport); \
  3491. THING(hriOut.pvReport, this->hriOut.cbReport); \
  3492. THING(hriFea.pvReport, this->hriFea.cbReport); \
  3493. THING(pvPhys, this->cbPhys); \
  3494. THING(pvStage, this->cbPhys); \
  3495. /*
  3496. * Make a pass through the fields adding up the memory requirements.
  3497. */
  3498. #define THING(f, cbF) cb += cbF
  3499. cb = 0;
  3500. THINGS();
  3501. #undef THING
  3502. hres = ReallocCbPpv(cb, &this->pvGroup2);
  3503. if(SUCCEEDED(hres))
  3504. {
  3505. PV pv;
  3506. /*
  3507. * Assert that the allocation is aligned
  3508. */
  3509. AssertF( !( ((UINT_PTR)this->pvGroup2) & ( MAX_NATURAL_ALIGNMENT - 1 ) ) );
  3510. /*
  3511. * Make a pass through the fields carving up the memory block
  3512. * and handing out pieces of it.
  3513. */
  3514. #define THING(f, cbF) this->f = pv; pv = pvAddPvCb(pv, cbF)
  3515. pv = this->pvGroup2;
  3516. THINGS();
  3517. #undef THING
  3518. /*
  3519. * There should be no byte left over.
  3520. */
  3521. AssertF(pvAddPvCb(this->pvGroup2, cb) == pv);
  3522. }
  3523. #undef THINGS
  3524. return hres;
  3525. }
  3526. /*****************************************************************************
  3527. *
  3528. * @doc INTERNAL
  3529. *
  3530. * @method HRESULT | CHid | InitParseData |
  3531. *
  3532. * Post-init pass to set up all the data used by parsing.
  3533. *
  3534. *****************************************************************************/
  3535. HRESULT EXTERNAL
  3536. CHid_InitParseData(PCHID this)
  3537. {
  3538. HRESULT hres;
  3539. UINT uiObj;
  3540. /*
  3541. * Preinitialize the HIDP_DATA indices to -1 to indicate
  3542. * that they aren't there. We must do this before we
  3543. * mess with AddDeviceData, which assumes that all the
  3544. * indices are properly set up.
  3545. */
  3546. for(uiObj = 0; uiObj < this->df.dwNumObjs; uiObj++)
  3547. {
  3548. this->rghoc[uiObj].idata = -1;
  3549. }
  3550. /*
  3551. * Now do some initialization of each object.
  3552. */
  3553. for(uiObj = 0; uiObj < this->df.dwNumObjs; uiObj++)
  3554. {
  3555. PHIDGROUPCAPS pcaps = this->rghoc[uiObj].pcaps;
  3556. LPDIOBJECTDATAFORMAT podf = &this->df.rgodf[uiObj];
  3557. /*
  3558. * ISSUE-2001/03/13-MarcAnd Should we panic if this assertion fails?
  3559. */
  3560. AssertF(pcaps);
  3561. if(pcaps)
  3562. {
  3563. /*
  3564. * For input-like objects, we need to initialize the
  3565. * physical state fields to sane defaults so apps
  3566. * don't get confused if they issue a read before the first
  3567. * report arrives.
  3568. *
  3569. * Buttons start out not pressed, which means we don't need
  3570. * to do anything since it's already zero-initialized.
  3571. *
  3572. * Relative axes start out not moving, which means we don't need
  3573. * to do anything since it's already zero-initialized.
  3574. *
  3575. * Absolute axes start out centered.
  3576. *
  3577. * POVs start out neutral.
  3578. *
  3579. */
  3580. /* No calibration for features as they are input / output */
  3581. if(pcaps->type == HidP_Input )
  3582. {
  3583. LONG UNALIGNED * pl;
  3584. pl = pvAddPvCb(this->pvPhys, podf->dwOfs);
  3585. if(podf->dwType & DIDFT_ABSAXIS )
  3586. {
  3587. if( this->rghoc[uiObj].pjrc->fRaw )
  3588. *pl = (this->rghoc[uiObj].pcaps->Logical.Min + this->rghoc[uiObj].pcaps->Logical.Max) / 2;
  3589. else
  3590. *pl = this->rghoc[uiObj].pjrc->lC;
  3591. } else if(podf->dwType & DIDFT_POV)
  3592. {
  3593. *pl = JOY_POVCENTERED;
  3594. }
  3595. }
  3596. /*
  3597. * ISSUE-2001/03/13-MarcAnd output objects uninitialized
  3598. * For output-like objects, we would have liked to have set the
  3599. * value to Null if possible to keep things vaguely sane.
  3600. * Unfortunately code like:
  3601. * if(HidP_IsOutputLike(pcaps->type))
  3602. * {
  3603. * CHid_AddDeviceData(this, uiObj,pcaps->Null);
  3604. * }
  3605. * Does not work!
  3606. */
  3607. }
  3608. }
  3609. hres = S_OK;
  3610. return hres;
  3611. }
  3612. /*****************************************************************************
  3613. *
  3614. * @doc INTERNAL
  3615. *
  3616. * @method HRESULT | CHid | InitAttributes |
  3617. *
  3618. * Pull out the <t HIDD_ATTRIBUTES> and squirrel away the
  3619. * information we like. Doing this up front is important
  3620. * in case the device gets unplugged later and we lose the
  3621. * ability to talk to it.
  3622. *
  3623. * @parm PHIDD_ATTRIBUTES | pattr |
  3624. *
  3625. * <t HIDD_ATTRIBUTES> containing attributes of device.
  3626. *
  3627. *****************************************************************************/
  3628. HRESULT EXTERNAL
  3629. CHid_InitAttributes(PCHID this, PHIDD_ATTRIBUTES pattr)
  3630. {
  3631. HRESULT hres;
  3632. TCHAR tszType[20];
  3633. #ifndef UNICODE
  3634. WCHAR wszType[20];
  3635. #endif
  3636. int ctch;
  3637. // Input report is disabled until we read flags2 from registry.
  3638. this->fEnableInputReport = FALSE;
  3639. this->fFlags2Checked = FALSE;
  3640. this->ProductID = pattr->ProductID;
  3641. this->VendorID = pattr->VendorID;
  3642. AssertF(this->hkType == 0);
  3643. if( ( this->VendorID == MSFT_SYSTEM_VID )
  3644. &&( ( this->ProductID >= MSFT_SYSTEM_PID + JOY_HW_PREDEFMIN )
  3645. &&( this->ProductID < MSFT_SYSTEM_PID + JOY_HW_PREDEFMAX ) ) )
  3646. {
  3647. /*
  3648. * Predefined types don't have keys
  3649. */
  3650. }
  3651. else
  3652. {
  3653. /*
  3654. * The type key for HID devices is "VID_xxxx&PID_yyyy",
  3655. * mirroring the format used by plug and play.
  3656. */
  3657. ctch = wsprintf(tszType, VID_PID_TEMPLATE,
  3658. this->VendorID, this->ProductID);
  3659. AssertF(ctch < cA(tszType));
  3660. #ifdef UNICODE
  3661. hres = JoyReg_OpenTypeKey(tszType, MAXIMUM_ALLOWED, REG_OPTION_NON_VOLATILE, &this->hkType);
  3662. JoyReg_OpenPropKey(tszType, MAXIMUM_ALLOWED, REG_OPTION_NON_VOLATILE, &this->hkProp);
  3663. /*
  3664. * If we fail to open the prop key - we will continue to function with loss in functionality
  3665. * Specifically no device images, etc
  3666. */
  3667. #else
  3668. TToU(wszType, cA(wszType), tszType);
  3669. hres = JoyReg_OpenTypeKey(wszType, MAXIMUM_ALLOWED, REG_OPTION_NON_VOLATILE, &this->hkType);
  3670. JoyReg_OpenPropKey(wszType, MAXIMUM_ALLOWED, REG_OPTION_NON_VOLATILE, &this->hkProp);
  3671. /*
  3672. * If we fail to open the prop key - we will continue to function with loss in functionality
  3673. * Specifically no device images, etc
  3674. */
  3675. #endif
  3676. /*
  3677. * It is not a problem if we can't open the type key.
  3678. * The device will run suboptimally, but it will still run.
  3679. */
  3680. AssertF(fLeqvFF(SUCCEEDED(hres), this->hkType));
  3681. }
  3682. hres = S_OK;
  3683. return hres;
  3684. }
  3685. /*****************************************************************************
  3686. *
  3687. * @doc INTERNAL
  3688. *
  3689. * @func BOOL | CHid_DoPathAndIdMatch |
  3690. *
  3691. * Given a device name, obtain the corresponding path
  3692. * ("device interface") associated with it, and check
  3693. * that it's the right string.
  3694. *
  3695. * @parm LPCTSTR | ptszId |
  3696. *
  3697. * The device name.
  3698. *
  3699. * @parm LPCTSTR | ptszPath |
  3700. *
  3701. * The path we should get back.
  3702. *
  3703. *****************************************************************************/
  3704. BOOL INTERNAL
  3705. CHid_DoPathAndIdMatch(LPCTSTR ptszId, LPCTSTR ptszPath)
  3706. {
  3707. GUID guidHid;
  3708. HDEVINFO hdev;
  3709. BOOL fRc;
  3710. HidD_GetHidGuid(&guidHid);
  3711. hdev = SetupDiGetClassDevs(&guidHid, ptszId, 0,
  3712. DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
  3713. if(hdev != INVALID_HANDLE_VALUE)
  3714. {
  3715. SP_DEVICE_INTERFACE_DATA did;
  3716. PSP_DEVICE_INTERFACE_DETAIL_DATA pdidd;
  3717. /*
  3718. * SetupDI requires that the caller initialize cbSize.
  3719. */
  3720. did.cbSize = cbX(did);
  3721. if(SetupDiEnumDeviceInterfaces(hdev, 0, &guidHid, 0, &did))
  3722. {
  3723. pdidd = NULL;
  3724. if(DIHid_GetDevicePath(hdev, &did, &pdidd, NULL))
  3725. {
  3726. fRc = ( lstrcmpi(pdidd->DevicePath, ptszPath) == 0x0 );
  3727. if( fRc == FALSE )
  3728. {
  3729. SquirtSqflPtszV(sqflHidParse | sqflError,
  3730. TEXT("pdidd->DevicePath = %s")
  3731. TEXT("ptszPath = %s "),
  3732. pdidd->DevicePath, ptszPath
  3733. );
  3734. }
  3735. FreePv(pdidd);
  3736. } else // GetDevicePath FAILED
  3737. {
  3738. fRc = FALSE;
  3739. SquirtSqflPtszV(sqflHidParse,
  3740. TEXT("GetDevicePath FAILED"));
  3741. }
  3742. } else // SetupDiEnumDeviceInterface FAILED
  3743. {
  3744. fRc = FALSE;
  3745. SquirtSqflPtszV(sqflHidParse,
  3746. TEXT("SetupDiEnumDeviceInterface FAILED"));
  3747. }
  3748. SetupDiDestroyDeviceInfoList(hdev);
  3749. } else // SetupDiGetClassDevs FAILED
  3750. {
  3751. fRc = FALSE;
  3752. SquirtSqflPtszV(sqflHidParse,
  3753. TEXT("SetupDiGetClassDevs FAILED"));
  3754. }
  3755. return fRc;
  3756. }
  3757. /*****************************************************************************
  3758. *
  3759. * @doc INTERNAL
  3760. *
  3761. * @method HRESULT | CHid | IsPolledDevice |
  3762. *
  3763. * Returns true if this device has to be polled for input data
  3764. * False if this device supports event driven input
  3765. *
  3766. * @parm HANDLE | hdev |
  3767. *
  3768. * File Handle to a HID device
  3769. *
  3770. *****************************************************************************/
  3771. BOOL EXTERNAL CHid_IsPolledDevice( HANDLE hdev )
  3772. {
  3773. /*
  3774. * To determine if a device is polled, we send it an IOCTL to set its
  3775. * poll frequency. If the device responds with a, huh!
  3776. * (STATUS_INVALID_DEVICE_REQUEST) then we know the device is not polled.
  3777. * On Win2k we use the poll interval value zero which is a special value
  3778. * that signals HID that we want to do opportunistic polls rather than
  3779. * polls on a background timer. In this case, as long as polls are not
  3780. * faster than the predefined minimum (currently 5ms) the poll will be
  3781. * completed either with recent data or the result of an immediate poll.
  3782. * On Win98 Gold opportunistic polls are not implemented so we always
  3783. * use HIDs background polling, with an interval set to keep the device
  3784. * responsive without swamping the system. To make sure we use a read
  3785. * thread, rather than a blocking read, we have to treat this devices as
  3786. * interrupt driven.
  3787. * HID makes this change the polling interval specific to our handle so
  3788. * that other apps reading from this device will not be damaged.
  3789. */
  3790. BOOL frc;
  3791. ULONG uPollingFreq;
  3792. DWORD cbRc;
  3793. #ifdef WINNT
  3794. BOOL fRet;
  3795. uPollingFreq = 0;
  3796. #else
  3797. uPollingFreq = 40;
  3798. #endif
  3799. frc = DeviceIoControl (hdev,
  3800. IOCTL_HID_SET_POLL_FREQUENCY_MSEC,
  3801. &uPollingFreq, cbX(uPollingFreq),
  3802. &uPollingFreq, cbX(uPollingFreq),
  3803. &cbRc, NULL);
  3804. #ifdef WINNT
  3805. if( frc )
  3806. {
  3807. SquirtSqflPtszV(sqflHidParse,
  3808. TEXT("CHid_IsPolledDevice: Opportunistic polling set") );
  3809. fRet = TRUE;
  3810. } else
  3811. {
  3812. SquirtSqflPtszV(sqflHidParse,
  3813. TEXT("CHid_IsPolledDevice: NOT POLLED, LastError = 0x%x"),
  3814. GetLastError());
  3815. fRet = FALSE;
  3816. }
  3817. return fRet;
  3818. #else
  3819. return FALSE;
  3820. #endif
  3821. }
  3822. /*****************************************************************************
  3823. *
  3824. * @doc INTERNAL
  3825. *
  3826. * @func HANDLE | CHid_OpenDevicePath |
  3827. *
  3828. * Given a device name, open the device via its
  3829. * device interface.
  3830. *
  3831. * @parm LPCTSTR | ptszId |
  3832. *
  3833. * @parm DWORD | dwAttributes |
  3834. *
  3835. * Create File attributes
  3836. *
  3837. * The device name.
  3838. *
  3839. *****************************************************************************/
  3840. HANDLE EXTERNAL
  3841. CHid_OpenDevicePath(PCHID this, DWORD dwAttributes)
  3842. {
  3843. HANDLE hDev;
  3844. hDev = CreateFile(this->ptszPath,
  3845. GENERIC_READ | GENERIC_WRITE,
  3846. FILE_SHARE_READ | FILE_SHARE_WRITE,
  3847. 0, /* no SECURITY_ATTRIBUTES */
  3848. OPEN_EXISTING,
  3849. dwAttributes, /* attributes */
  3850. 0); /* template */
  3851. if( hDev == INVALID_HANDLE_VALUE )
  3852. {
  3853. SquirtSqflPtszV(sqflHidParse | sqflBenign,
  3854. TEXT("Failed to open HID %s, le=%d"), this->ptszPath, GetLastError() );
  3855. }
  3856. this->IsPolledInput = CHid_IsPolledDevice(hDev);
  3857. return hDev;
  3858. }
  3859. /*****************************************************************************
  3860. *
  3861. * @doc INTERNAL
  3862. *
  3863. * @method HRESULT | CHid | GetHdevInfo |
  3864. *
  3865. * Get information about the device that is kept in the
  3866. * HANDLE itself. We create the handle, get the goo, and
  3867. * then close the handle.
  3868. *
  3869. * The preparsed data is stashed into the <e CHid.ppd>
  3870. * field of the <t CHid> structure.
  3871. *
  3872. * @parm PHIDD_ATTRIBUTES | pattr |
  3873. *
  3874. * Receives the <t HIDD_ATTRIBUTES> of the device.
  3875. *
  3876. *****************************************************************************/
  3877. BOOL INTERNAL
  3878. CHid_GetHdevInfo(PCHID this, PHIDD_ATTRIBUTES pattr)
  3879. {
  3880. HANDLE hdev;
  3881. BOOL fRc = FALSE;
  3882. hdev = CHid_OpenDevicePath(this, FILE_FLAG_OVERLAPPED);
  3883. if(hdev != INVALID_HANDLE_VALUE)
  3884. {
  3885. pattr->Size = cbX(*pattr);
  3886. if( HidD_GetAttributes(hdev, pattr) )
  3887. {
  3888. if( HidD_GetPreparsedData(hdev, &this->ppd) )
  3889. {
  3890. fRc = TRUE;
  3891. }
  3892. else
  3893. {
  3894. RPF( "HidD_GetPreparsedData failed, le=%d", GetLastError() );
  3895. }
  3896. }
  3897. else
  3898. {
  3899. RPF( "HidD_GetAttributes failed, le=%d", GetLastError() );
  3900. }
  3901. CloseHandle(hdev);
  3902. }
  3903. return fRc;
  3904. }
  3905. /*****************************************************************************
  3906. *
  3907. * @doc INTERNAL
  3908. *
  3909. * @method HRESULT | CHid | Init |
  3910. *
  3911. * Initialize the object.
  3912. *
  3913. *****************************************************************************/
  3914. HRESULT EXTERNAL
  3915. CHid_Init(PCHID this, REFGUID rguid)
  3916. {
  3917. HRESULT hres = E_FAIL;
  3918. PHIDDEVICEINFO phdi;
  3919. EnterProc(CHid_Init, (_ "p", this));
  3920. SquirtSqflPtszV(sqflHidParse,
  3921. TEXT("CHid_Init: Starting %08x"), rguid->Data1);
  3922. this->df.dwSize = cbX(DIDATAFORMAT);
  3923. this->df.dwObjSize = cbX(DIOBJECTDATAFORMAT);
  3924. AssertF(this->df.dwDataSize == 0);
  3925. AssertF(this->df.rgodf == 0);
  3926. AssertF(this->df.dwFlags == 0);
  3927. AssertF(this->df.dwNumObjs == 0);
  3928. AssertF(this->dwAxes == 0);
  3929. AssertF(this->dwButtons == 0);
  3930. AssertF(this->dwCollections == 0);
  3931. this->idJoy = -1; /* Unknown associated VJOYD device */
  3932. this->hdev = INVALID_HANDLE_VALUE;
  3933. this->hdevEm = INVALID_HANDLE_VALUE;
  3934. this->diHacks.nMaxDeviceNameLength = MAX_PATH;
  3935. DllEnterCrit();
  3936. phdi = phdiFindHIDInstanceGUID(rguid);
  3937. if(phdi)
  3938. {
  3939. this->dwDevType = phdi->osd.dwDevType;
  3940. this->idJoy = phdi->idJoy;
  3941. /*
  3942. * Dup the registry key so we can hang onto it after
  3943. * the original has been closed. If the RegOpenKeyEx
  3944. * fails, the value of this->hkInstType will stay zero
  3945. * so we won't run with garbage.
  3946. */
  3947. AssertF(this->hkInstType == 0);
  3948. hres = hresMumbleKeyEx(phdi->hk,
  3949. TEXT("Type"),
  3950. DI_KEY_ALL_ACCESS,
  3951. REG_OPTION_NON_VOLATILE,
  3952. &this->hkInstType);
  3953. /*
  3954. * Dup the paths and stuff.
  3955. */
  3956. hres = hresDupPtszPptsz(phdi->pdidd->DevicePath, &this->ptszPath);
  3957. if(SUCCEEDED(hres))
  3958. {
  3959. hres = hresDupPtszPptsz(phdi->ptszId, &this->ptszId);
  3960. }
  3961. }
  3962. /*
  3963. * Get out of the critical section as quickly as possible.
  3964. * Note phdi is invalid once we leave the critical section however
  3965. * we can safely use is as a flag that the GUID was found.
  3966. */
  3967. DllLeaveCrit();
  3968. if(phdi)
  3969. {
  3970. if(SUCCEEDED(hres))
  3971. {
  3972. HIDD_ATTRIBUTES attr;
  3973. if( !CHid_GetHdevInfo(this, &attr) )
  3974. {
  3975. SquirtSqflPtszV(sqflHidParse | sqflError,
  3976. TEXT("%hs: CHid_GetHdevInfo failed"), s_szProc );
  3977. hres = E_FAIL;
  3978. }
  3979. else if( FAILED(HidP_GetCaps(this->ppd, &this->caps) ) )
  3980. {
  3981. SquirtSqflPtszV(sqflHidParse | sqflError,
  3982. TEXT("%hs: HidP_GetCaps failed, le=%d"), s_szProc, GetLastError() );
  3983. hres = E_FAIL;
  3984. }
  3985. else if( !CHid_DoPathAndIdMatch(this->ptszId, this->ptszPath) )
  3986. {
  3987. SquirtSqflPtszV(sqflHidParse | sqflError,
  3988. TEXT("%hs: Path and HW ID do not match"), s_szProc );
  3989. hres = E_FAIL;
  3990. }
  3991. else
  3992. {
  3993. if(SUCCEEDED(hres = CHid_InitAttributes(this, &attr)) &&
  3994. SUCCEEDED(hres = CHid_AllocObjectMemory(this)) &&
  3995. SUCCEEDED(hres = CHid_InitObjects(this)) &&
  3996. SUCCEEDED(hres = CHid_InitParse(this)) &&
  3997. SUCCEEDED(hres = CHid_InitParseData(this)))
  3998. {
  3999. VXDDEVICEFORMAT devf;
  4000. UINT uiCal;
  4001. /*
  4002. * Load calibration information, and if there were
  4003. * no calibratable items, then wipe out this->pjrcNext
  4004. * to indicate that there is no need to watch for
  4005. * recalibration messages.
  4006. */
  4007. uiCal = CHid_LoadCalibrations(this);
  4008. if(uiCal == 0)
  4009. {
  4010. this->pjrcNext = NULL;
  4011. }
  4012. /*
  4013. * Remember to do this after we have
  4014. * created the data format.
  4015. */
  4016. devf.cbData = this->df.dwDataSize;
  4017. devf.cObj = this->df.dwNumObjs;
  4018. devf.rgodf = this->df.rgodf;
  4019. /*
  4020. * Note, dwExtra is 64 bits on 64 bit platforms
  4021. * should update the name one day.
  4022. */
  4023. devf.dwExtra = (UINT_PTR)this;
  4024. devf.dwEmulation = 0;
  4025. hres = Hel_HID_CreateInstance(&devf, &this->pvi);
  4026. /* Polled input devices may not be attached */
  4027. if(this->IsPolledInput)
  4028. {
  4029. HANDLE hdev;
  4030. PBUSDEVICEINFO pbdi;
  4031. hdev = CHid_OpenDevicePath(this, 0x0);
  4032. if( hdev != INVALID_HANDLE_VALUE )
  4033. {
  4034. int i;
  4035. BOOL frc;
  4036. DWORD cbRead;
  4037. BOOL bPresent = FALSE;
  4038. for( i=0x0; i < FAILED_POLL_THRESHOLD; i++ )
  4039. {
  4040. frc = ReadFile(hdev, this->hriIn.pvReport,
  4041. this->hriIn.cbReport, &cbRead, 0x0 );
  4042. if( frc != 0x0 &&
  4043. cbRead == this->hriIn.cbReport )
  4044. {
  4045. bPresent = TRUE;
  4046. break;
  4047. } else
  4048. {
  4049. Sleep(10);
  4050. SquirtSqflPtszV(sqflHidParse | sqflVerbose,
  4051. TEXT("CHid_Init: ReadFailed, LastError = 0x%x"),
  4052. GetLastError());
  4053. }
  4054. }
  4055. CloseHandle(hdev);
  4056. if( bPresent == FALSE )
  4057. {
  4058. this->pvi->fl |= VIFL_UNPLUGGED;
  4059. SquirtSqflPtszV(sqflHidParse | sqflBenign,
  4060. TEXT("%hs: ReadFailed, setting to unplugged"), s_szProc );
  4061. }
  4062. DllEnterCrit();
  4063. phdi = phdiFindHIDDeviceInterface(this->ptszPath);
  4064. AssertF(phdi != NULL);
  4065. pbdi = pbdiFromphdi(phdi);
  4066. DllLeaveCrit();
  4067. if( pbdi != NULL )
  4068. {
  4069. if( pbdi->fDeleteIfNotConnected == TRUE )
  4070. {
  4071. if( bPresent == FALSE )
  4072. {
  4073. lstrcpy( g_tszIdLastRemoved, pbdi->ptszId );
  4074. g_tmLastRemoved = GetTickCount();
  4075. DIBusDevice_Remove(pbdi);
  4076. }
  4077. pbdi->fDeleteIfNotConnected = FALSE;
  4078. }
  4079. }
  4080. } else
  4081. {
  4082. // Could not Open the device
  4083. this->pvi->fl |= VIFL_UNPLUGGED;
  4084. }
  4085. }
  4086. }
  4087. }
  4088. }
  4089. } else
  4090. {
  4091. // Squirt: device mysteriously gone
  4092. hres = DIERR_DEVICENOTREG;
  4093. }
  4094. SquirtSqflPtszV(sqflHidParse,
  4095. TEXT("CHid_Init: Ending %08x"), rguid->Data1);
  4096. ExitOleProc();
  4097. return hres;
  4098. }