Source code of Windows XP (NT5)
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.

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