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.

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