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.

3626 lines
105 KiB

  1. /*****************************************************************************
  2. *
  3. * DIGenJ.c
  4. *
  5. * Copyright (c) 1996 - 2000 Microsoft Corporation. All Rights Reserved.
  6. *
  7. * Abstract:
  8. *
  9. * Generic IDirectInputDevice callback for joystick.
  10. *
  11. * Contents:
  12. *
  13. * CJoy_CreateInstance
  14. *
  15. *****************************************************************************/
  16. #include "dinputpr.h"
  17. #ifndef WINNT
  18. /*****************************************************************************
  19. *
  20. * The sqiffle for this file.
  21. *
  22. *****************************************************************************/
  23. #define sqfl sqflJoy
  24. /*****************************************************************************
  25. *
  26. * Declare the interfaces we will be providing.
  27. *
  28. * WARNING! If you add a secondary interface, you must also change
  29. * CJoy_New!
  30. *
  31. *****************************************************************************/
  32. Primary_Interface(CJoy, IDirectInputDeviceCallback);
  33. /*****************************************************************************
  34. *
  35. * Macro "lookup tables".
  36. *
  37. * iJoyStateAxis# converts an axis name to an axis number in the
  38. * DIJOYSTATE structure.
  39. *
  40. * ibJoyStateAxis# converts the name to an offset.
  41. *
  42. * Note that the extra axes in DIJOYSTATE2 are arranged in relative
  43. * positions just like a DIJOYSTATE. We will exploit this
  44. * arrangement frequently.
  45. *
  46. *****************************************************************************/
  47. #define iJoyStateAxisX 0
  48. #define iJoyStateAxisY 1
  49. #define iJoyStateAxisZ 2
  50. #define iJoyStateAxisRx 3
  51. #define iJoyStateAxisRy 4
  52. #define iJoyStateAxisRz 5
  53. #define iJoyStateAxisS0 6
  54. #define iJoyStateAxisS1 7
  55. #define cJoyStateAxisMax 8
  56. #define iJoyStateAxisSlider iJoyStateAxisS0 /* Hack for macros */
  57. #define cJoyStateAxis 8
  58. #define iobjPositions (cJoyStateAxis * 0)
  59. #define iobjVelocities (cJoyStateAxis * 1)
  60. #define iobjAccels (cJoyStateAxis * 2)
  61. #define iobjForces (cJoyStateAxis * 3)
  62. #define cJoyStateAxisTotal (cJoyStateAxis * 4)
  63. #define ibJoyStateAxisX (iJoyStateAxisX * cbX(LONG))
  64. #define ibJoyStateAxisY (iJoyStateAxisY * cbX(LONG))
  65. #define ibJoyStateAxisZ (iJoyStateAxisZ * cbX(LONG))
  66. #define ibJoyStateAxisRx (iJoyStateAxisRx * cbX(LONG))
  67. #define ibJoyStateAxisRy (iJoyStateAxisRy * cbX(LONG))
  68. #define ibJoyStateAxisRz (iJoyStateAxisRz * cbX(LONG))
  69. #define ibJoyStateAxisS0 (iJoyStateAxisS0 * cbX(LONG))
  70. #define ibJoyStateAxisS1 (iJoyStateAxisS1 * cbX(LONG))
  71. #define ibJoyStateAxisSlider ibJoyStateAxisS0 /* Hack for macros */
  72. #define cJoyStatePOVTotal 4
  73. #define cJoyStateButtonTotal 128
  74. #define cJoyStateObjTotal (cJoyStateAxisTotal + \
  75. cJoyStatePOVTotal + \
  76. cJoyStateButtonTotal)
  77. /*
  78. * The worst-case data format for joysticks. (Christmas-tree)
  79. */
  80. VXDAXISCAPS c_vacMax = {
  81. JOYPF_ALLCAPS | JOYPF_POSITION, /* dwPos */
  82. JOYPF_ALLCAPS | JOYPF_VELOCITY, /* dwVel */
  83. JOYPF_ALLCAPS | JOYPF_ACCELERATION, /* dwAccel */
  84. JOYPF_ALLCAPS | JOYPF_FORCE, /* dwForce */
  85. };
  86. /*****************************************************************************
  87. *
  88. * @doc INTERNAL
  89. *
  90. * @func UINT | ibJoyStateAxisFromPosAxis |
  91. *
  92. * Returns the offset of the <p iPosAxis>'th joystick axis
  93. * in the <t DIJOYSTATE> structure.
  94. *
  95. * @parm UINT | uiStateAxis |
  96. *
  97. * The index of the requested <t JOYPOS> axis.
  98. * X, Y, Z, R, U and V are respectively zero through five.
  99. *
  100. * Remember that we map R to Rz, U to Slider0 and V to Slider1.
  101. *
  102. * @returns
  103. *
  104. * The offset relative to the structure.
  105. *
  106. *****************************************************************************/
  107. const int c_rgibJoyStateAxisFromPosAxis[6] = {
  108. FIELD_OFFSET(DIJOYSTATE, lX), /* X */
  109. FIELD_OFFSET(DIJOYSTATE, lY), /* Y */
  110. FIELD_OFFSET(DIJOYSTATE, lZ), /* Z */
  111. FIELD_OFFSET(DIJOYSTATE, lRz), /* R */
  112. FIELD_OFFSET(DIJOYSTATE, rglSlider[0]), /* U */
  113. FIELD_OFFSET(DIJOYSTATE, rglSlider[1]), /* V */
  114. };
  115. UINT INLINE
  116. ibJoyStateAxisFromPosAxis(UINT uiPosAxis)
  117. {
  118. AssertF(uiPosAxis < cA(c_rgibJoyStateAxisFromPosAxis));
  119. return c_rgibJoyStateAxisFromPosAxis[uiPosAxis];
  120. }
  121. /*****************************************************************************
  122. *
  123. * @doc INTERNAL
  124. *
  125. * @func UINT | iJoyStateAxisFromPosAxis |
  126. *
  127. * Returns the index of the <p iPosAxis>'th joystick axis
  128. * in the <t DIJOYSTATE> structure.
  129. *
  130. * @parm UINT | uiStateAxis |
  131. *
  132. * The index of the requested <t JOYPOS> axis.
  133. * X, Y, Z, R, U and V are respectively zero through five.
  134. *
  135. * Remember that we map R to Rz, U to Slider0 and V to Slider1.
  136. *
  137. * @returns
  138. *
  139. * The offset relative to the structure.
  140. *
  141. *****************************************************************************/
  142. const int c_rgiJoyStateAxisFromPosAxis[6] = {
  143. iJoyStateAxisX, /* X */
  144. iJoyStateAxisY, /* Y */
  145. iJoyStateAxisZ, /* Z */
  146. iJoyStateAxisRz, /* R */
  147. iJoyStateAxisS0, /* U */
  148. iJoyStateAxisS1, /* V */
  149. };
  150. UINT INLINE
  151. iJoyStateAxisFromPosAxis(UINT uiPosAxis)
  152. {
  153. AssertF(uiPosAxis < cA(c_rgiJoyStateAxisFromPosAxis));
  154. return c_rgiJoyStateAxisFromPosAxis[uiPosAxis];
  155. }
  156. /*****************************************************************************
  157. *
  158. * @doc INTERNAL
  159. *
  160. * @func UINT | ibJoyStateAxisFromStateAxis |
  161. *
  162. * Returns the offset of the <p iStateAxis>'th joystick axis
  163. * in the <t DIJOYSTATE> structure.
  164. *
  165. * @parm UINT | uiStateAxis |
  166. *
  167. * The index of the requested <t JOYSTATE> axis.
  168. * The first eight axes live at the top, and the
  169. * later ones (corresponding to velocity, etc.)
  170. * live down at the bottom.
  171. *
  172. * @returns
  173. *
  174. * The offset relative to the structure.
  175. *
  176. *****************************************************************************/
  177. const int c_rgibJoyStateAxisFromStateAxis[cJoyStateAxisMax] = {
  178. FIELD_OFFSET(DIJOYSTATE, lX), /* X */
  179. FIELD_OFFSET(DIJOYSTATE, lY), /* Y */
  180. FIELD_OFFSET(DIJOYSTATE, lZ), /* Z */
  181. FIELD_OFFSET(DIJOYSTATE, lRx), /* Rx */
  182. FIELD_OFFSET(DIJOYSTATE, lRy), /* Ry */
  183. FIELD_OFFSET(DIJOYSTATE, lRz), /* Rz */
  184. FIELD_OFFSET(DIJOYSTATE, rglSlider[0]), /* S0 */
  185. FIELD_OFFSET(DIJOYSTATE, rglSlider[1]), /* S1 */
  186. };
  187. UINT INLINE
  188. ibJoyStateAxisFromStateAxis(UINT uiStateAxis)
  189. {
  190. AssertF(uiStateAxis < cA(c_rgibJoyStateAxisFromStateAxis));
  191. return c_rgibJoyStateAxisFromStateAxis[uiStateAxis];
  192. }
  193. /*****************************************************************************
  194. *
  195. * @doc INTERNAL
  196. *
  197. * @func UINT | iJoyPosAxisFromStateAxis |
  198. *
  199. * Convert a <t DIJOYSTATE> axis number back to
  200. * a <t JOYPOS> axis number.
  201. *
  202. * @parm UINT | uiPosAxis |
  203. *
  204. * The index of the requested <t JOYSTATE> axis.
  205. *
  206. * @returns
  207. *
  208. * The corresponding <t JOYPOS> axis number.
  209. *
  210. *****************************************************************************/
  211. const int c_rgiJoyPosAxisFromStateAxis[8] = {
  212. iJoyPosAxisX, /* X */
  213. iJoyPosAxisY, /* Y */
  214. iJoyPosAxisZ, /* Z */
  215. -1, /* Rx */
  216. -1, /* Ry */
  217. iJoyPosAxisR, /* Rz */
  218. iJoyPosAxisU, /* S0 */
  219. iJoyPosAxisV, /* S1 */
  220. };
  221. UINT INLINE
  222. iJoyPosAxisFromStateAxis(UINT uiStateAxis)
  223. {
  224. AssertF(uiStateAxis < cA(c_rgiJoyPosAxisFromStateAxis));
  225. return c_rgiJoyPosAxisFromStateAxis[uiStateAxis];
  226. }
  227. /*****************************************************************************
  228. *
  229. * @doc INTERNAL
  230. *
  231. * @topic Cooking Joystick Data |
  232. *
  233. * We always fetch joystick data raw, then cook it before
  234. * returning it to the application.
  235. *
  236. * If the app is in "raw" mode, then we don't cook anything.
  237. *
  238. * If the app is in "cooked" mode, then things get interesting.
  239. *
  240. * If there is `centered' cooking, then the center point of the
  241. * joystick is reported in the center of the virtual range.
  242. *
  243. *
  244. * Joystick properties work like this:
  245. *
  246. * <c DIPROP_BUFFERSIZE> - No special semantics.
  247. *
  248. * <c DIPROP_CALIBRATIONMODE> - Specifies whether
  249. * cooked or raw data should be returned. If raw data
  250. * is requested, then most other properties have no effect.
  251. *
  252. * The default is cooked.
  253. *
  254. * <c DIPROP_GRANULARITY> - No special semantics.
  255. *
  256. * <c DIPROP_RANGE> - This returns the range of values that
  257. * can be returned by the axis. For joysticks, this is a
  258. * read/write property. (For most devices, it is a read-only
  259. * property.) If you change the property, it affects only
  260. * your device instance; it does not affect the ranges of other
  261. * devices.
  262. *
  263. * If the axis is in calibration mode, then setting this value
  264. * has no immediate effect.
  265. *
  266. * We also define a few new properties:
  267. *
  268. * <c DIPROP_CENTER> - This returns the joystick center (neutral)
  269. * position. In other words, this is the position that
  270. * DirectInput returns when the user has released the joystick
  271. * and allowed it to self-center.
  272. * When a joystick device is created, the center position is
  273. * initially set to midway between the lower and
  274. * upper bounds of the range. An application may change the
  275. * center position (although I don't see any reason why).
  276. *
  277. * If the axis is in calibration mode, then setting this value
  278. * has no immediate effect.
  279. *
  280. * <c DIPROP_DEADZONE> - This returns the size of the joystick
  281. * dead zone, as a percentage of total range.
  282. *
  283. * If the axis is in calibration mode, then setting this value
  284. * has no immediate effect.
  285. *
  286. *****************************************************************************/
  287. /*****************************************************************************
  288. *
  289. * @doc INTERNAL
  290. *
  291. * @struct CJoy |
  292. *
  293. * The <i IDirectInputDeviceCallback> object for the
  294. * generic joystick.
  295. *
  296. * @field IDirectInputDeviceCallback | didc |
  297. *
  298. * The object (containing vtbl).
  299. *
  300. * @field PDIJOYSTATE2 | pjsPhys |
  301. *
  302. * Pointer to physical joystick status information kept down in the
  303. * VxD.
  304. *
  305. * @field UINT | idJoy |
  306. *
  307. * Joystick identifier for <f joyGetPosEx> and friends.
  308. *
  309. * @field DWORD | dwPOVGranularity |
  310. *
  311. * Granularity of the POV control.
  312. *
  313. * @field HWND | hwnd |
  314. *
  315. * The window which we have subclassed in order to watch
  316. * for joystick reconfiguration messages.
  317. *
  318. * @field HKEY | hkType |
  319. *
  320. * The joystick type key opened with <c MAXIMUM_ALLOWED> access.
  321. *
  322. * @field VXDINSTANCE * | pvi |
  323. *
  324. * The DirectInput instance handle.
  325. *
  326. * @field DIDEVCAPS | dc |
  327. *
  328. * Device capability information.
  329. *
  330. * @field DIDATAFORMAT | df |
  331. *
  332. * The dynamically-generated data format based on the
  333. * joystick type.
  334. *
  335. * @field JOYRANGECONVERT | rgjrc |
  336. *
  337. * Range conversion structures for each axis.
  338. *
  339. * @field DIJOYCONFIG | cfg |
  340. *
  341. * Joystick configuration information.
  342. *
  343. * @field DIJOYTYPEINFO | typi |
  344. *
  345. * Joystick type information.
  346. *
  347. * @field PDIDOBJDEFSEM | rgObjSem |
  348. *
  349. * Pointer to array of semantics mapped to this device,
  350. * calculated during init.
  351. *
  352. * @field DWORD | dwVersion |
  353. *
  354. * DirectInput version requested by application
  355. *
  356. * @field DIAPPHACKS | diHacks |
  357. *
  358. * Application hack flags
  359. *
  360. * @field HKEY | hkProp |
  361. *
  362. * Extended properties for device type. Currently we keep
  363. * OEMMapFile under this key.
  364. *
  365. * @comm
  366. *
  367. * It is the caller's responsibility to serialize access as
  368. * necessary.
  369. *
  370. *****************************************************************************/
  371. typedef struct CJoy {
  372. /* Supported interfaces */
  373. IDirectInputDeviceCallback dcb;
  374. LPDIJOYSTATE2 pjsPhys;
  375. UINT idJoy;
  376. DWORD dwPOVGranularity;
  377. HWND hwnd;
  378. HKEY hkType;
  379. VXDINSTANCE *pvi;
  380. DIDEVCAPS dc;
  381. DIDATAFORMAT df;
  382. JOYRANGECONVERT rgjrc[cJoyStateAxisMax];
  383. DIJOYCONFIG cfg;
  384. DIJOYTYPEINFO typi;
  385. PDIDOBJDEFSEM rgObjSem;
  386. DWORD dwVersion;
  387. DIAPPHACKS diHacks;
  388. HKEY hkProp;
  389. } CJoy, DJ, *PDJ;
  390. #define ThisClass CJoy
  391. #define ThisInterface IDirectInputDeviceCallback
  392. #define riidExpected &IID_IDirectInputDeviceCallback
  393. /*****************************************************************************
  394. *
  395. * Forward declarations
  396. *
  397. * These are out of laziness, not out of necessity.
  398. *
  399. *****************************************************************************/
  400. STDMETHODIMP CJoy_GetFFConfigKey(PDICB pdcb, DWORD sam, PHKEY phk);
  401. void INTERNAL CJoy_InitPhysRanges(PDJ this, LPJOYREGHWCONFIG phwc);
  402. LRESULT CALLBACK
  403. CJoy_SubclassProc(HWND hwnd, UINT wm, WPARAM wp, LPARAM lp,
  404. UINT uid, ULONG_PTR dwRef);
  405. /*****************************************************************************
  406. *
  407. * CJoy::QueryInterface (from IUnknown)
  408. * CJoy::AddRef (from IUnknown)
  409. * CJoy::Release (from IUnknown)
  410. *
  411. *****************************************************************************/
  412. /*****************************************************************************
  413. *
  414. * @doc INTERNAL
  415. *
  416. * @method HRESULT | CJoy | QueryInterface |
  417. *
  418. * Gives a client access to other interfaces on an object.
  419. *
  420. * @parm IN REFIID | riid |
  421. *
  422. * The requested interface's IID.
  423. *
  424. * @parm OUT LPVOID * | ppvObj |
  425. *
  426. * Receives a pointer to the obtained interface.
  427. *
  428. * @returns
  429. *
  430. * Returns a COM error code.
  431. *
  432. * @xref OLE documentation for <mf IUnknown::QueryInterface>.
  433. *
  434. *****************************************************************************
  435. *
  436. * @doc INTERNAL
  437. *
  438. * @method HRESULT | CJoy | AddRef |
  439. *
  440. * Increments the reference count for the interface.
  441. *
  442. * @returns
  443. *
  444. * Returns the object reference count.
  445. *
  446. * @xref OLE documentation for <mf IUnknown::AddRef>.
  447. *
  448. *****************************************************************************
  449. *
  450. * @doc INTERNAL
  451. *
  452. * @method HRESULT | CJoy | Release |
  453. *
  454. * Decrements the reference count for the interface.
  455. * If the reference count on the object falls to zero,
  456. * the object is freed from memory.
  457. *
  458. * @returns
  459. *
  460. * Returns the object reference count.
  461. *
  462. * @xref OLE documentation for <mf IUnknown::Release>.
  463. *
  464. *****************************************************************************
  465. *
  466. * @doc INTERNAL
  467. *
  468. * @method HRESULT | CJoy | QIHelper |
  469. *
  470. * We don't have any dynamic interfaces and simply forward
  471. * to <f Common_QIHelper>.
  472. *
  473. * @parm IN REFIID | riid |
  474. *
  475. * The requested interface's IID.
  476. *
  477. * @parm OUT LPVOID * | ppvObj |
  478. *
  479. * Receives a pointer to the obtained interface.
  480. *
  481. *****************************************************************************
  482. *
  483. * @doc INTERNAL
  484. *
  485. * @method HRESULT | CJoy | AppFinalize |
  486. *
  487. * We don't have any weak pointers, so we can just
  488. * forward to <f Common_Finalize>.
  489. *
  490. * @parm PV | pvObj |
  491. *
  492. * Object being released from the application's perspective.
  493. *
  494. *****************************************************************************/
  495. #ifdef DEBUG
  496. Default_QueryInterface(CJoy)
  497. Default_AddRef(CJoy)
  498. Default_Release(CJoy)
  499. #else
  500. #define CJoy_QueryInterface Common_QueryInterface
  501. #define CJoy_AddRef Common_AddRef
  502. #define CJoy_Release Common_Release
  503. #endif
  504. #define CJoy_QIHelper Common_QIHelper
  505. /*****************************************************************************
  506. *
  507. * @doc INTERNAL
  508. *
  509. * @method void | CJoy | RemoveSubclass |
  510. *
  511. * Remove our subclass hook on the window.
  512. *
  513. * The parameter is intentionally misdeclared as a <t PV>
  514. * so that this function can double as the <f CJoy_AppFinalize>.
  515. *
  516. *****************************************************************************/
  517. void INTERNAL
  518. CJoy_RemoveSubclass(PV pvObj)
  519. {
  520. PDJ this = pvObj;
  521. /*
  522. * If there was an old window, then un-subclass it
  523. * and release the hold associated with it.
  524. *
  525. * You might think that there's a race condition here, where
  526. * we might unhold the device while the subclass procedure is
  527. * still using it.
  528. *
  529. * Ah, but that's not a problem, because the only message that
  530. * the subclass procedure cares about is the joystick
  531. * reconfiguration message, and when it is processing that message,
  532. * it does its own artificial hold/unhold to keep the device alive
  533. * while it dorks on the device.
  534. *
  535. * Okay, so there *is* a really tiny race condition where we
  536. * might nuke the device while the window procedure is studying
  537. * the message to decide whether it cares or not.
  538. *
  539. * Since that is so extremely rare, we close that window by
  540. * hacking it: We revalidate the device before partying on it.
  541. * Note that the hack is not perfect, but the race window becomes
  542. * only a few instructions long that I'm not going to worry about it.
  543. *
  544. * By wiping out this->hwnd before removing the subclass, we
  545. * can reduce the window to very small indeed.
  546. */
  547. if (this->hwnd) {
  548. HWND hwnd = this->hwnd;
  549. this->hwnd = 0;
  550. if (!RemoveWindowSubclass(hwnd, CJoy_SubclassProc, 0)) {
  551. /*
  552. * The RemoveWindowSubclass can fail if the window
  553. * was destroyed behind our back.
  554. */
  555. // AssertF(!IsWindow(hwnd));
  556. }
  557. Sleep(0); /* Let the worker thread drain */
  558. Common_Unhold(this);
  559. }
  560. }
  561. /*****************************************************************************
  562. *
  563. * @doc INTERNAL
  564. *
  565. * @func void | CJoy_Finalize |
  566. *
  567. * Releases the resources of the device.
  568. *
  569. * @parm PV | pvObj |
  570. *
  571. * Object being released. Note that it may not have been
  572. * completely initialized, so everything should be done
  573. * carefully.
  574. *
  575. *****************************************************************************/
  576. void INTERNAL
  577. CJoy_Finalize(PV pvObj)
  578. {
  579. PDJ this = pvObj;
  580. if (this->pvi) {
  581. HRESULT hres;
  582. hres = Hel_DestroyInstance(this->pvi);
  583. AssertF(SUCCEEDED(hres));
  584. FreePpv(&this->df.rgodf);
  585. FreePpv(&this->rgObjSem );
  586. if (this->hkType) {
  587. RegCloseKey(this->hkType);
  588. }
  589. if( this->hkProp) {
  590. RegCloseKey(this->hkProp);
  591. }
  592. }
  593. }
  594. /*****************************************************************************
  595. *
  596. * @doc INTERNAL
  597. *
  598. * @func void | CJoy_AppFinalize |
  599. *
  600. * The application has performed its final release.
  601. * Remove our window subclass at this point.
  602. *
  603. * @parm PV | pvObj |
  604. *
  605. * Object being released. Note that it may not have been
  606. * completely initialized, so everything should be done
  607. * carefully.
  608. *
  609. *****************************************************************************/
  610. #define CJoy_AppFinalize CJoy_RemoveSubclass
  611. /*****************************************************************************
  612. *
  613. * @doc INTERNAL
  614. *
  615. * @func LRESULT | CJoy_SubclassProc |
  616. *
  617. * Window subclass procedure which watches for
  618. * joystick configuration change notifications.
  619. *
  620. * @parm HWND | hwnd |
  621. *
  622. * The victim window.
  623. *
  624. * @parm UINT | wm |
  625. *
  626. * Window message.
  627. *
  628. * @parm WPARAM | wp |
  629. *
  630. * Message-specific data.
  631. *
  632. * @parm LPARAM | lp |
  633. *
  634. * Message-specific data.
  635. *
  636. * @parm UINT | uid |
  637. *
  638. * Callback identification number, always zero.
  639. *
  640. * @parm DWORD | dwRef |
  641. *
  642. * Reference data, a pointer to our joystick device callback.
  643. *
  644. *****************************************************************************/
  645. LRESULT CALLBACK
  646. CJoy_SubclassProc(HWND hwnd, UINT wm, WPARAM wp, LPARAM lp,
  647. UINT uid, ULONG_PTR dwRef)
  648. {
  649. #ifdef XDEBUG
  650. static CHAR s_szProc[] = "";
  651. #endif
  652. AssertF(uid == 0);
  653. if (wm == g_wmJoyChanged) {
  654. PDJ this = (PDJ)dwRef;
  655. /*
  656. * Wacky subtlety going on here to avoid race conditions.
  657. * See the mondo comment block in CJoy_RemoveSubclass
  658. * for details.
  659. *
  660. * We can get faked out if the memory associated with the
  661. * CJoy is still physically allocated, the vtbl is magically
  662. * still there and the hwnd field somehow matches our hwnd.
  663. */
  664. if (SUCCEEDED(hresPv(this)) && this->hwnd == hwnd) {
  665. HRESULT hres;
  666. Common_Hold(this);
  667. /*
  668. * We must ask for DIJC_CALLOUT even though we don't care,
  669. * because that will trigger the Microsoft Gamepad hack-o-rama.
  670. *
  671. * Also, make sure we don't decide that we tried recently
  672. */
  673. #ifndef WINNT
  674. g_dwLastBonusPoll = GetTickCount() ^ 0x80000000;
  675. #endif
  676. hres = JoyReg_GetConfig(this->idJoy, &this->cfg,
  677. DIJC_REGHWCONFIGTYPE | DIJC_CALLOUT);
  678. if (SUCCEEDED(hres)) {
  679. CJoy_InitPhysRanges(this, &this->cfg.hwc);
  680. }
  681. Common_Unhold(this);
  682. }
  683. }
  684. return DefSubclassProc(hwnd, wm, wp, lp);
  685. }
  686. /*****************************************************************************
  687. *
  688. * @doc INTERNAL
  689. *
  690. * @method HRESULT | CJoy | GetInstance |
  691. *
  692. * Obtains the DirectInput instance handle.
  693. *
  694. * @parm OUT PPV | ppvi |
  695. *
  696. * Receives the instance handle.
  697. *
  698. *****************************************************************************/
  699. STDMETHODIMP
  700. CJoy_GetInstance(PDICB pdcb, PPV ppvi)
  701. {
  702. HRESULT hres;
  703. PDJ this;
  704. EnterProcI(IDirectInputDeviceCallback::Joy::GetInstance, (_ "p", pdcb));
  705. /*
  706. * This is an internal interface, so we can skimp on validation.
  707. */
  708. this = _thisPvNm(pdcb, dcb);
  709. *ppvi = (PV)this->pvi;
  710. hres = S_OK;
  711. ExitOleProcPpvR(ppvi);
  712. return hres;
  713. }
  714. /*****************************************************************************
  715. *
  716. * @doc INTERNAL
  717. *
  718. * @method HRESULT | CJoy | GetDataFormat |
  719. *
  720. * Obtains the device's preferred data format.
  721. *
  722. * @parm OUT LPDIDEVICEFORMAT * | ppdf |
  723. *
  724. * <t LPDIDEVICEFORMAT> to receive pointer to device format.
  725. *
  726. * @returns
  727. *
  728. * Returns a COM error code. The following error codes are
  729. * intended to be illustrative and not necessarily comprehensive.
  730. *
  731. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  732. *
  733. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: The
  734. * <p lpmdr> parameter is not a valid pointer.
  735. *
  736. *****************************************************************************/
  737. STDMETHODIMP
  738. CJoy_GetDataFormat(PDICB pdcb, LPDIDATAFORMAT *ppdf)
  739. {
  740. HRESULT hres;
  741. PDJ this;
  742. EnterProcI(IDirectInputDeviceCallback::Joy::GetDataFormat,
  743. (_ "p", pdcb));
  744. /*
  745. * This is an internal interface, so we can skimp on validation.
  746. */
  747. this = _thisPvNm(pdcb, dcb);
  748. *ppdf = &this->df;
  749. hres = S_OK;
  750. ExitOleProcPpvR(ppdf);
  751. return hres;
  752. }
  753. /*****************************************************************************
  754. *
  755. * @doc INTERNAL
  756. *
  757. * @method HRESULT | CJoy | GetDeviceInfo |
  758. *
  759. * Obtain general information about the device.
  760. *
  761. * @parm OUT LPDIDEVICEINSTANCEW | pdiW |
  762. *
  763. * <t DEVICEINSTANCE> to be filled in. The
  764. * <e DEVICEINSTANCE.dwSize> and <e DEVICEINSTANCE.guidInstance>
  765. * have already been filled in.
  766. *
  767. * Secret convenience: <e DEVICEINSTANCE.guidProduct> is equal
  768. * to <e DEVICEINSTANCE.guidInstance>.
  769. *
  770. *****************************************************************************/
  771. STDMETHODIMP
  772. CJoy_GetDeviceInfo(PDICB pdcb, LPDIDEVICEINSTANCEW pdiW)
  773. {
  774. HRESULT hres;
  775. PDJ this;
  776. EnterProcI(IDirectInputDeviceCallback::Joy::GetDeviceInfo,
  777. (_ "pp", pdcb, pdiW));
  778. /*
  779. * This is an internal interface, so we can skimp on validation.
  780. */
  781. this = _thisPvNm(pdcb, dcb);
  782. AssertF(IsValidSizeDIDEVICEINSTANCEW(pdiW->dwSize));
  783. /*
  784. * Unlike mouse and keyboard, there can be multiple instances of
  785. * the same joystick product, so we can't just leave guidProduct
  786. * equal to guidInstance.
  787. */
  788. pdiW->guidProduct = GUID_Joystick;
  789. AssertF(pdiW->guidInstance.Data1 ==
  790. (pdiW->guidProduct.Data1 | this->idJoy));
  791. pdiW->dwDevType = this->dc.dwDevType;
  792. #ifdef UNICODE
  793. lstrcpyn(pdiW->tszProductName, this->typi.wszDisplayName,
  794. cA(pdiW->tszProductName));
  795. #else
  796. CAssertF(cA(pdiW->tszProductName) >= cA(this->typi.wszDisplayName));
  797. CopyMemory(pdiW->tszProductName, this->typi.wszDisplayName,
  798. cbX(this->typi.wszDisplayName));
  799. #endif
  800. /*
  801. * Since we use HID path, there is no meaning to distinguish
  802. * the devices by using "Joystick x" name.
  803. * We'd better use the same DisplayName for InstanceName.
  804. * Shall we do this?
  805. *
  806. LoadString(g_hinst, IDS_STDJOYSTICK, tszFormat, cA(tszFormat));
  807. #ifdef UNICODE
  808. wsprintf(pdiW->tszInstanceName, tszFormat, this->idJoy + 1);
  809. #else
  810. wsprintf(tszName, tszFormat, this->idJoy + 1);
  811. AToU(pdiW->tszInstanceName, cA(pdiW->tszInstanceName), tszName);
  812. #endif
  813. */
  814. #ifdef UNICODE
  815. lstrcpyn(pdiW->tszInstanceName, this->typi.wszDisplayName,
  816. cA(pdiW->tszInstanceName));
  817. #else
  818. CAssertF(cA(pdiW->tszInstanceName) >= cA(this->typi.wszDisplayName));
  819. CopyMemory(pdiW->tszInstanceName, this->typi.wszDisplayName,
  820. cbX(this->typi.wszDisplayName));
  821. #endif
  822. if (pdiW->dwSize >= cbX(DIDEVICEINSTANCE_DX5W)) {
  823. HKEY hkFF;
  824. /*
  825. * If there is a force feedback driver, then fetch the driver CLSID
  826. * as the FF GUID.
  827. */
  828. hres = CJoy_GetFFConfigKey(pdcb, KEY_QUERY_VALUE, &hkFF);
  829. if (SUCCEEDED(hres)) {
  830. LONG lRc;
  831. TCHAR tszClsid[ctchGuid];
  832. lRc = RegQueryString(hkFF, TEXT("CLSID"), tszClsid, cA(tszClsid));
  833. if (lRc == ERROR_SUCCESS &&
  834. ParseGUID(&pdiW->guidFFDriver, tszClsid)) {
  835. } else {
  836. ZeroX(pdiW->guidFFDriver);
  837. }
  838. RegCloseKey(hkFF);
  839. }
  840. }
  841. hres = S_OK;
  842. ExitOleProcR();
  843. return hres;
  844. }
  845. /*****************************************************************************
  846. *
  847. * @doc INTERNAL
  848. *
  849. * @method void | CJoy | SetAxisProperty |
  850. *
  851. * If the request is to set a property on the device,
  852. * then convert it into separate requests, one for each
  853. * axis.
  854. *
  855. * @parm PDJ | this |
  856. *
  857. * The device object.
  858. *
  859. * @parm GETSETJOYPROP | GetSetJoyProp |
  860. *
  861. * Callback function that gets or sets the property.
  862. *
  863. * @parm IN LPCDIPROPINFO | ppropi |
  864. *
  865. * Information describing the property being set.
  866. *
  867. * @parm LPCDIPROPHEADER | pdiph |
  868. *
  869. * Structure containing property value.
  870. *
  871. * @parm int | ibField |
  872. *
  873. * Offset to field being set. (Really: Reference data to
  874. * pass to callback.)
  875. *
  876. *****************************************************************************/
  877. STDMETHODIMP
  878. CJoy_SetAxisProperty(PDJ this, LPCDIPROPINFO ppropi, LPCDIPROPHEADER pdiph)
  879. {
  880. HRESULT hres;
  881. /*
  882. * Note that we never pass the type key to CCal_SetProperty
  883. * because we keep our calibration data elsewhere.
  884. */
  885. if (ppropi->dwDevType == 0) { /* For device */
  886. int iAxis;
  887. for (iAxis = 0; iAxis < cA(this->rgjrc); iAxis++) {
  888. PJOYRANGECONVERT pjrc = &this->rgjrc[iAxis];
  889. hres = CCal_SetProperty(pjrc, ppropi, pdiph, NULL);
  890. if (FAILED(hres)) {
  891. goto done;
  892. }
  893. }
  894. hres = S_OK;
  895. } else if ((ppropi->dwDevType & DIDFT_ABSAXIS) &&
  896. DIDFT_GETINSTANCE(ppropi->dwDevType) < cA(this->rgjrc)) {
  897. PJOYRANGECONVERT pjrc;
  898. pjrc = &this->rgjrc[DIDFT_GETINSTANCE(ppropi->dwDevType)];
  899. hres = CCal_SetProperty(pjrc, ppropi, pdiph, NULL);
  900. } else {
  901. hres = E_NOTIMPL;
  902. }
  903. done:;
  904. return hres;
  905. }
  906. /*****************************************************************************
  907. *
  908. * @doc INTERNAL
  909. *
  910. * @method void | CJoy | UpdateAxisCalibration |
  911. *
  912. * Take our cached calibration information and smash it into
  913. * the configuration section of the registry.
  914. *
  915. * @parm PDJ | this |
  916. *
  917. * The device object.
  918. *
  919. *****************************************************************************/
  920. STDMETHODIMP
  921. CJoy_UpdateAxisCalibration(PDJ this)
  922. {
  923. HRESULT hres;
  924. DIJOYCONFIG cfg;
  925. hres = JoyReg_GetConfig(this->idJoy, &cfg, DIJC_REGHWCONFIGTYPE);
  926. if (SUCCEEDED(hres)) {
  927. UINT uiPosAxis;
  928. #define JoyPosValue(phwc, f, i) \
  929. *(LPDWORD)pvAddPvCb(&(phwc)->hwv.jrvHardware.f, \
  930. ibJoyPosAxisFromPosAxis(i)) \
  931. for (uiPosAxis = 0; uiPosAxis < cJoyPosAxisMax; uiPosAxis++) {
  932. PJOYRANGECONVERT pjrc;
  933. UINT uiStateAxis;
  934. uiStateAxis = iJoyStateAxisFromPosAxis(uiPosAxis);
  935. pjrc = &this->rgjrc[uiStateAxis];
  936. JoyPosValue(&cfg.hwc, jpMin, uiPosAxis) = pjrc->dwPmin;
  937. JoyPosValue(&cfg.hwc, jpMax, uiPosAxis) = pjrc->dwPmax;
  938. JoyPosValue(&cfg.hwc, jpCenter, uiPosAxis) = pjrc->dwPc;
  939. #undef JoyPosValue
  940. }
  941. hres = JoyReg_SetConfig(this->idJoy, &cfg.hwc, &cfg,
  942. DIJC_UPDATEALIAS | DIJC_REGHWCONFIGTYPE);
  943. }
  944. if (FAILED(hres)) {
  945. RPF("Joystick::SetProperty::Calibration: "
  946. "Unable to update calibration in registry");
  947. }
  948. return hres;
  949. }
  950. /*****************************************************************************
  951. *
  952. * @doc INTERNAL
  953. *
  954. * @method HRESULT | CJoy | SetProperty |
  955. *
  956. * Set a device property.
  957. *
  958. * @parm PDJ | this |
  959. *
  960. * The device object.
  961. *
  962. * @parm IN LPCDIPROPINFO | ppropi |
  963. *
  964. * Information describing the property being set.
  965. *
  966. * @parm LPCDIPROPHEADER | pdiph |
  967. *
  968. * Structure containing property value.
  969. *
  970. * @returns
  971. *
  972. * <c E_NOTIMPL> for something we didn't handle natively.
  973. * The caller will do
  974. * the default thing in response to <c E_NOTIMPL>.
  975. *
  976. *****************************************************************************/
  977. STDMETHODIMP
  978. CJoy_SetProperty(PDICB pdcb, LPCDIPROPINFO ppropi, LPCDIPROPHEADER pdiph)
  979. {
  980. HRESULT hres;
  981. PDJ this;
  982. EnterProcI(IDirectInputDeviceCallback::Joy::SetProperty,
  983. (_ "pxxp", pdcb, ppropi->pguid, ppropi->iobj, pdiph));
  984. /*
  985. * This is an internal interface, so we can skimp on validation.
  986. */
  987. this = _thisPvNm(pdcb, dcb);
  988. switch ((DWORD)(UINT_PTR)ppropi->pguid) {
  989. case (DWORD)(UINT_PTR)DIPROP_RANGE:
  990. case (DWORD)(UINT_PTR)DIPROP_DEADZONE:
  991. case (DWORD)(UINT_PTR)DIPROP_SATURATION:
  992. case (DWORD)(UINT_PTR)DIPROP_CALIBRATIONMODE:
  993. case (DWORD)(UINT_PTR)DIPROP_CALIBRATION:
  994. hres = CJoy_SetAxisProperty(this, ppropi, pdiph);
  995. if (SUCCEEDED(hres) && ppropi->pguid == DIPROP_CALIBRATION) {
  996. hres = CJoy_UpdateAxisCalibration(this);
  997. }
  998. break;
  999. case (DWORD)(UINT_PTR)DIPROP_INSTANCENAME:
  1000. case (DWORD)(UINT_PTR)DIPROP_PRODUCTNAME:
  1001. {
  1002. USHORT uVid, uPid;
  1003. /*
  1004. * Friendly names cause all manner of problems with devices that
  1005. * use auto detection so only allow non-predefined analog devices
  1006. * to use them.
  1007. *
  1008. * Prefix warns (240487) that ParseVIDPID could leave uVid
  1009. * uninitialized and succeed but it won't.
  1010. * See the comment in _ParseHex for more details.
  1011. */
  1012. if( ParseVIDPID( &uVid, &uPid, this->cfg.wszType ) &&
  1013. ( uVid == MSFT_SYSTEM_VID ) &&
  1014. ( uPid >= MSFT_SYSTEM_PID + JOY_HW_PREDEFMAX ) &&
  1015. ( ( uPid & 0xff00 ) == MSFT_SYSTEM_PID ) )
  1016. {
  1017. AssertF(this->hkType);
  1018. if( this->hkType )
  1019. {
  1020. LPDIPROPSTRING pstr = (PV)pdiph;
  1021. hres = JoyReg_SetValue(this->hkType,
  1022. REGSTR_VAL_JOYOEMNAME, REG_SZ,
  1023. pstr->wsz,
  1024. cbX(pstr->wsz));
  1025. if( SUCCEEDED(hres ) )
  1026. {
  1027. hres = S_OK;
  1028. } else {
  1029. hres = E_FAIL;
  1030. }
  1031. }
  1032. }
  1033. else
  1034. {
  1035. hres = E_NOTIMPL;
  1036. }
  1037. break;
  1038. }
  1039. default:
  1040. SquirtSqflPtszV(sqflJoy,
  1041. TEXT("CJoy_SetProperty: E_NOTIMPL on guid: %08x"),
  1042. ppropi->pguid);
  1043. hres = E_NOTIMPL;
  1044. break;
  1045. }
  1046. ExitOleProcR();
  1047. return hres;
  1048. }
  1049. /*****************************************************************************
  1050. *
  1051. * @doc INTERNAL
  1052. *
  1053. * @method HRESULT | CJoy | GetAxisProperty |
  1054. *
  1055. * Handle an axis property.
  1056. *
  1057. * @cwrap PDJ | this
  1058. *
  1059. * @parm IN LPCDIPROPINFO | ppropi |
  1060. *
  1061. * Information describing the property being retrieved.
  1062. *
  1063. * @parm OUT LPDIPROPHEADER | pdiph |
  1064. *
  1065. * Structure to receive property value.
  1066. *
  1067. * @returns
  1068. *
  1069. * <c S_OK> if the operation completed successfully.
  1070. *
  1071. * <c E_NOTIMPL> nothing happened. The caller will do
  1072. * the default thing in response to <c E_NOTIMPL>.
  1073. *
  1074. *****************************************************************************/
  1075. STDMETHODIMP
  1076. CJoy_GetAxisProperty(PDJ this, LPCDIPROPINFO ppropi, LPDIPROPHEADER pdiph)
  1077. {
  1078. LPDIPROPRANGE pdiprg = (PV)pdiph;
  1079. HRESULT hres;
  1080. if ((ppropi->dwDevType & DIDFT_ABSAXIS) &&
  1081. DIDFT_GETINSTANCE(ppropi->dwDevType) < cA(this->rgjrc)) {
  1082. PJOYRANGECONVERT pjrc;
  1083. pjrc = &this->rgjrc[DIDFT_GETINSTANCE(ppropi->dwDevType)];
  1084. hres = CCal_GetProperty(pjrc, ppropi->pguid, pdiph);
  1085. } else {
  1086. SquirtSqflPtszV(sqflJoy,
  1087. TEXT("CJoy_GetProperty: E_NOTIMPL on guid: %08x"),
  1088. ppropi->pguid);
  1089. hres = E_NOTIMPL;
  1090. }
  1091. return hres;
  1092. }
  1093. /*****************************************************************************
  1094. *
  1095. * @doc INTERNAL
  1096. *
  1097. * @method void | CJoy | GetGuidAndPath |
  1098. *
  1099. * Get a Joy device's class GUID (namely, the MEDIA guid)
  1100. * and device interface (path). The path is for the equivalent
  1101. * HID device if possible, otherwise a NULL string.
  1102. *
  1103. * @parm PCHID | this |
  1104. *
  1105. * The Joy object.
  1106. *
  1107. * @parm LPDIPROPHEADER | pdiph |
  1108. *
  1109. * Structure to receive property value.
  1110. *
  1111. *****************************************************************************/
  1112. VOID INTERNAL
  1113. CJoy_GetGuidAndPath(PDJ this, LPDIPROPHEADER pdiph)
  1114. {
  1115. /*
  1116. * This should never happen on Win2k because all devices are HID
  1117. * but just in case we build an NT4 SP5 version or something...
  1118. */
  1119. #ifdef WINNT
  1120. LPDIPROPGUIDANDPATH pgp = (PV)pdiph;
  1121. UNREFERENCED_PARAMETER( this );
  1122. pgp->guidClass = GUID_MediaClass;
  1123. pgp->wszPath[0] = TEXT( '\0' );
  1124. #else
  1125. LPDIPROPGUIDANDPATH pgp = (PV)pdiph;
  1126. VXDINITPARMS vip;
  1127. TCHAR szPath[MAX_PATH];
  1128. PTCHAR pszPath;
  1129. pgp->guidClass = GUID_MediaClass;
  1130. pszPath = JoyReg_JoyIdToDeviceInterface_95( this->idJoy, &vip, szPath );
  1131. if( pszPath )
  1132. {
  1133. TToU( pgp->wszPath, cA(pgp->wszPath), pszPath );
  1134. }
  1135. else
  1136. {
  1137. pgp->wszPath[0] = TEXT( '\0' );
  1138. }
  1139. #endif
  1140. }
  1141. /*****************************************************************************
  1142. *
  1143. * @doc INTERNAL
  1144. *
  1145. * @method HRESULT | CJoy | GetProperty |
  1146. *
  1147. * Retrieve a device property.
  1148. *
  1149. * @parm PDJ | this |
  1150. *
  1151. * The device object.
  1152. *
  1153. * @parm IN LPCDIPROPINFO | ppropi |
  1154. *
  1155. * Information describing the property being retrieved.
  1156. *
  1157. * @parm LPDIPROPHEADER | pdiph |
  1158. *
  1159. * Structure to receive property value.
  1160. *
  1161. * @returns
  1162. *
  1163. * <c S_OK> if the operation completed successfully.
  1164. *
  1165. * <c E_NOTIMPL> nothing happened. The caller will do
  1166. * the default thing in response to <c E_NOTIMPL>.
  1167. *
  1168. *****************************************************************************/
  1169. STDMETHODIMP
  1170. CJoy_GetProperty(PDICB pdcb, LPCDIPROPINFO ppropi, LPDIPROPHEADER pdiph)
  1171. {
  1172. HRESULT hres = E_NOTIMPL;
  1173. PDJ this;
  1174. EnterProcI(IDirectInputDeviceCallback::Joy::GetProperty,
  1175. (_ "pxxp", pdcb, ppropi->pguid, ppropi->iobj, pdiph));
  1176. /*
  1177. * This is an internal interface, so we can skimp on validation.
  1178. */
  1179. this = _thisPvNm(pdcb, dcb);
  1180. switch ((DWORD)(UINT_PTR)ppropi->pguid) {
  1181. case (DWORD)(UINT_PTR)DIPROP_GRANULARITY:
  1182. /*
  1183. * ISSUE-2001/03/29-timgill All POVs have the same granularity
  1184. */
  1185. if (ppropi->dwDevType & DIDFT_POV) {
  1186. LPDIPROPDWORD pdipdw = (PV)pdiph;
  1187. pdipdw->dwData = this->dwPOVGranularity;
  1188. hres = S_OK;
  1189. }
  1190. break;
  1191. case (DWORD)(UINT_PTR)DIPROP_GUIDANDPATH:
  1192. if(ppropi->iobj == 0xFFFFFFFF)
  1193. {
  1194. CJoy_GetGuidAndPath(this, pdiph);
  1195. hres = S_OK;
  1196. }
  1197. break;
  1198. /*
  1199. * In DX7, INSTANCENAME and PRODUCTNAME are the same for VJOYD devices.
  1200. * It is different before DX7. Probably we need make them different again
  1201. * after DX7.
  1202. */
  1203. case (DWORD)(UINT_PTR)DIPROP_INSTANCENAME:
  1204. case (DWORD)(UINT_PTR)DIPROP_PRODUCTNAME:
  1205. {
  1206. LPDIPROPSTRING pdipstr = (PV)pdiph;
  1207. /*
  1208. * lstrcpW doesn't work in Win95. We have to use memcpy instead.
  1209. */
  1210. //lstrcpyW(pstr->wsz, this->typi.wszDisplayName);
  1211. if( cbX(pdipstr->wsz) > cbX(this->typi.wszDisplayName) )
  1212. {
  1213. memset( &pdipstr->wsz[cA(this->typi.wszDisplayName)], 0, cbX(pdipstr->wsz) - cbX(this->typi.wszDisplayName) );
  1214. }
  1215. CAssertF( cbX(pdipstr->wsz) >= cbX(this->typi.wszDisplayName) );
  1216. memcpy( pdipstr->wsz, this->typi.wszDisplayName, cbX(this->typi.wszDisplayName));
  1217. if( this->diHacks.nMaxDeviceNameLength < lstrlenW(pdipstr->wsz) ) {
  1218. pdipstr->wsz[this->diHacks.nMaxDeviceNameLength] = L'\0';
  1219. }
  1220. hres = S_OK;
  1221. break;
  1222. }
  1223. case (DWORD)(UINT_PTR)DIPROP_JOYSTICKID:
  1224. if(ppropi->iobj == 0xFFFFFFFF)
  1225. {
  1226. LPDIPROPDWORD pdipdw = (PV)pdiph;
  1227. pdipdw->dwData = this->idJoy;
  1228. hres = S_OK;
  1229. }
  1230. break;
  1231. case (DWORD)(UINT_PTR)(DIPROP_MAPFILE):
  1232. AssertF( ppropi->iobj == 0xFFFFFFFF );
  1233. {
  1234. LPDIPROPSTRING pdipstr = (PV)pdiph;
  1235. LONG lRes;
  1236. DWORD dwBufferSize = cbX(pdipstr->wsz);
  1237. lRes = RegQueryStringValueW( this->hkProp, REGSTR_VAL_JOYOEMMAPFILE, pdipstr->wsz, &dwBufferSize );
  1238. hres = ( pdipstr->wsz[0] && ( lRes == ERROR_SUCCESS ) ) ? S_OK : DIERR_OBJECTNOTFOUND;
  1239. }
  1240. break;
  1241. case (DWORD)(UINT_PTR)(DIPROP_TYPENAME):
  1242. AssertF( ppropi->iobj == 0xFFFFFFFF );
  1243. {
  1244. LPDIPROPSTRING pdipstr = (PV)pdiph;
  1245. if( this->cfg.hwc.dwType >= JOY_HW_PREDEFMIN && this->cfg.hwc.dwType < JOY_HW_PREDEFMAX ) {
  1246. pdipstr->wsz[0] = L'#';
  1247. pdipstr->wsz[1] = L'0' + (WCHAR)this->cfg.hwc.dwType;
  1248. pdipstr->wsz[2] = L'\0';
  1249. hres = S_OK;
  1250. }
  1251. else if( this->cfg.wszType[0] != L'\0' )
  1252. {
  1253. /*
  1254. * The type MUST be NULL terminated
  1255. */
  1256. #ifdef WINNT
  1257. lstrcpyW( pdipstr->wsz, this->cfg.wszType );
  1258. #else
  1259. UINT uiLen;
  1260. uiLen = lstrlenW( this->cfg.wszType ) + 1;
  1261. AssertF( uiLen <= cA( pdipstr->wsz ) );
  1262. memcpy( pdipstr->wsz, this->cfg.wszType, uiLen * cbX(this->cfg.wszType[0]) );
  1263. #endif
  1264. hres = S_OK;
  1265. }
  1266. else
  1267. {
  1268. /*
  1269. * Don't think this should ever happen so Assert for now
  1270. * Assert that the hres is a failure (if not quite right)
  1271. */
  1272. AssertF( hres == E_NOTIMPL );
  1273. AssertF( !"No type name available in GetProperty" );
  1274. }
  1275. }
  1276. break;
  1277. /*
  1278. * Else, it might be something axis-specific.
  1279. */
  1280. default:
  1281. hres = CJoy_GetAxisProperty(this, ppropi, pdiph);
  1282. break;
  1283. }
  1284. ExitOleProcR();
  1285. return hres;
  1286. }
  1287. /*****************************************************************************
  1288. *
  1289. * @doc INTERNAL
  1290. *
  1291. * @method void | CJoy | GetCapabilities |
  1292. *
  1293. * Get joystick device capabilities.
  1294. *
  1295. * @parm PDJ | this |
  1296. *
  1297. * The joystick object.
  1298. *
  1299. * @parm LPDIDEVCAPS | pdc |
  1300. *
  1301. * Device capabilities structure to receive result.
  1302. *
  1303. * @returns
  1304. * <c S_OK> on success.
  1305. *
  1306. *****************************************************************************/
  1307. STDMETHODIMP
  1308. CJoy_GetCapabilities(PDICB pdcb, LPDIDEVCAPS pdc)
  1309. {
  1310. HRESULT hres;
  1311. PDJ this;
  1312. JOYINFOEX jix;
  1313. MMRESULT mmrc = MMSYSERR_ERROR;
  1314. EnterProcI(IDirectInputDeviceCallback::Joy::GetCapabilities,
  1315. (_ "pp", pdcb, pdc));
  1316. /*
  1317. * This is an internal interface, so we can skimp on validation.
  1318. */
  1319. this = _thisPvNm(pdcb, dcb);
  1320. AssertF(IsValidSizeDIDEVCAPS(pdc->dwSize));
  1321. CopyMemory(pvAddPvCb(pdc, cbX(DWORD)),
  1322. pvAddPvCb(&this->dc, cbX(DWORD)),
  1323. pdc->dwSize - cbX(DWORD));
  1324. /*
  1325. * Joysticks can come and go. Re-query each time.
  1326. */
  1327. /*
  1328. * Determine if joystick is physically attached
  1329. * or is possibly even phantom.
  1330. *
  1331. * JOYERR_ATTACHED - Is attached
  1332. * JOYERR_UNPLUGGED - Is not attached
  1333. * Anything else - Is phantom
  1334. */
  1335. jix.dwSize = sizeof(JOYINFOEX);
  1336. jix.dwFlags = JOY_CAL_READALWAYS | JOY_RETURNALL;
  1337. mmrc = joyGetPosEx(this->idJoy, &jix);
  1338. pdc->dwFlags &= ~DIDC_ATTACHED;
  1339. if (mmrc == JOYERR_NOERROR) {
  1340. pdc->dwFlags |= DIDC_ATTACHED;
  1341. } else if (mmrc == JOYERR_UNPLUGGED) {
  1342. } else {
  1343. pdc->dwFlags |= DIDC_PHANTOM;
  1344. }
  1345. hres = S_OK;
  1346. ExitOleProcR();
  1347. return hres;
  1348. }
  1349. /*****************************************************************************
  1350. *
  1351. * @doc INTERNAL
  1352. *
  1353. * @method void | CJoy | GetPhysicalState |
  1354. *
  1355. * Read the physical joystick state into <p pjsOut>.
  1356. *
  1357. * After getting the physical data,
  1358. * we cook the axes as necessary.
  1359. *
  1360. * @parm LPDIJOYSTATE2 | pjsOut |
  1361. *
  1362. * Where to put the joystick state.
  1363. *
  1364. * @returns
  1365. *
  1366. * None.
  1367. *
  1368. *****************************************************************************/
  1369. void INLINE
  1370. CJoy_GetPhysicalState(PDJ this, LPDIJOYSTATE2 pjsOut)
  1371. {
  1372. UINT uiStateAxis;
  1373. AssertF(this->pjsPhys);
  1374. *pjsOut = *this->pjsPhys;
  1375. /*
  1376. * Note only absolute positional data gets calibrated
  1377. */
  1378. if( ( this->pvi->fl & VIFL_RELATIVE ) == 0 )
  1379. {
  1380. for (uiStateAxis = 0; uiStateAxis < cA(this->rgjrc); uiStateAxis++) {
  1381. PLONG pl = pvAddPvCb(pjsOut,
  1382. ibJoyStateAxisFromStateAxis(uiStateAxis));
  1383. CCal_CookRange(&this->rgjrc[uiStateAxis], pl);
  1384. }
  1385. }
  1386. }
  1387. /*****************************************************************************
  1388. *
  1389. * @doc INTERNAL
  1390. *
  1391. * @method HRESULT | CJoy | Poll |
  1392. *
  1393. * Ping down into the driver to get the latest data.
  1394. *
  1395. * @returns
  1396. *
  1397. * <c S_OK> if we pinged okay.
  1398. * <c DIERR_UNPLUGGED> if we did not
  1399. *
  1400. *****************************************************************************/
  1401. STDMETHODIMP
  1402. CJoy_Poll(PDICB pdcb)
  1403. {
  1404. HRESULT hres;
  1405. PDJ this;
  1406. EnterProcI(IDirectInputDeviceCallback::Joy::Poll, (_ "p", pdcb));
  1407. /*
  1408. * This is an internal interface, so we can skimp on validation.
  1409. */
  1410. this = _thisPvNm(pdcb, dcb);
  1411. hres = Hel_Joy_Ping(this->pvi);
  1412. if (FAILED(hres)) {
  1413. AssertF(hres ==
  1414. MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32,
  1415. ERROR_DEV_NOT_EXIST));
  1416. hres = DIERR_UNPLUGGED;
  1417. }
  1418. /*
  1419. * Note, we don't keep this->pvi->fl:VIFL_UNPLUGGED up-to-date because
  1420. * we don't use the flag and always retest the connectivity in GetCaps.
  1421. */
  1422. return hres;
  1423. }
  1424. /*****************************************************************************
  1425. *
  1426. * @doc INTERNAL
  1427. *
  1428. * @method HRESULT | CJoy | GetDeviceState |
  1429. *
  1430. * Obtains the state of the joystick device.
  1431. *
  1432. * It is the caller's responsibility to have validated all the
  1433. * parameters and ensure that the device has been acquired.
  1434. *
  1435. * @parm OUT LPVOID | lpvData |
  1436. *
  1437. * joystick data in the preferred data format.
  1438. *
  1439. * @returns
  1440. *
  1441. * Returns a COM error code. The following error codes are
  1442. * intended to be illustrative and not necessarily comprehensive.
  1443. *
  1444. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  1445. *
  1446. * <c DIERR_INVALIDPARAM> = <c E_INVALIDARG>: The
  1447. * <p lpmdr> parameter is not a valid pointer.
  1448. *
  1449. *****************************************************************************/
  1450. STDMETHODIMP
  1451. CJoy_GetDeviceState(PDICB pdcb, LPVOID pvData)
  1452. {
  1453. HRESULT hres;
  1454. PDJ this;
  1455. LPDIJOYSTATE2 pjsOut = pvData;
  1456. EnterProcI(IDirectInputDeviceCallback::Joy::GetDeviceState,
  1457. (_ "pp", pdcb, pvData));
  1458. /*
  1459. * This is an internal interface, so we can skimp on validation.
  1460. */
  1461. this = _thisPvNm(pdcb, dcb);
  1462. AssertF(this->pvi);
  1463. AssertF(this->pjsPhys);
  1464. if (this->pvi->fl & VIFL_ACQUIRED) {
  1465. CJoy_GetPhysicalState(this, pjsOut);
  1466. hres = S_OK;
  1467. } else {
  1468. hres = DIERR_INPUTLOST;
  1469. }
  1470. ExitOleProcR();
  1471. return hres;
  1472. }
  1473. /*****************************************************************************
  1474. *
  1475. * @doc INTERNAL
  1476. *
  1477. * @method HRESULT | CJoy | CookDeviceData |
  1478. *
  1479. * Manipulate buffered device data.
  1480. *
  1481. * If the item describe an axis, we need to cook it.
  1482. *
  1483. * @parm DWORD | cdod |
  1484. *
  1485. * Number of objects to cook; zero is a valid value.
  1486. *
  1487. * @parm LPDIDEVICEOBJECTDATA | pdod |
  1488. *
  1489. * Array of object data to cook.
  1490. *
  1491. * @returns
  1492. *
  1493. * Returns a COM error code. The following error codes are
  1494. * intended to be illustrative and not necessarily comprehensive.
  1495. *
  1496. * <c DI_OK> = <c S_OK>: The operation completed successfully.
  1497. *
  1498. * <c DIERR_UNSUPPORTED> = <c E_NOTIMPL>: The callback does
  1499. * not cook device data.
  1500. *
  1501. * <c DIERR_NOTACQUIRED>: The device could not be acquired.
  1502. *
  1503. ***************************************************************************/
  1504. STDMETHODIMP
  1505. CJoy_CookDeviceData
  1506. (
  1507. PDICB pdcb,
  1508. DWORD cdod,
  1509. LPDIDEVICEOBJECTDATA pdod
  1510. )
  1511. {
  1512. HRESULT hres;
  1513. PDJ this;
  1514. EnterProcI(IDirectInputDeviceCallback::Joy::CookDeviceData,
  1515. (_ "pxp", pdcb, cdod, pdod));
  1516. /*
  1517. * This is an internal interface, so we can skimp on validation.
  1518. */
  1519. this = _thisPvNm(pdcb, dcb);
  1520. /*
  1521. * Step through array of either element size cooking the data.
  1522. */
  1523. for( ; cdod; cdod-- )
  1524. {
  1525. DWORD dwType = this->df.rgodf[pdod->dwOfs].dwType;
  1526. if( dwType & DIDFT_ABSAXIS )
  1527. {
  1528. PJOYRANGECONVERT pjrc;
  1529. AssertF( DIDFT_GETINSTANCE( dwType ) < cA( this->rgjrc ) );
  1530. pjrc = &this->rgjrc[DIDFT_GETINSTANCE( dwType )];
  1531. CCal_CookRange(pjrc, (PV)&pdod->dwData);
  1532. }
  1533. pdod++;
  1534. }
  1535. hres = S_OK;
  1536. return hres;
  1537. }
  1538. /*****************************************************************************
  1539. *
  1540. * @doc INTERNAL
  1541. *
  1542. * @method HRESULT | CJoy | OpenIdSubkey |
  1543. *
  1544. * Given an object ID, attempt to open the subkey that
  1545. * corresponds to it.
  1546. *
  1547. * @cwrap PDJ | this
  1548. *
  1549. * @parm DWORD | dwId |
  1550. *
  1551. * Object id.
  1552. *
  1553. * @parm PHKEY | phk |
  1554. *
  1555. * Receives the key on success.
  1556. *
  1557. * @returns
  1558. *
  1559. * Returns a COM error code.
  1560. *
  1561. *****************************************************************************/
  1562. HRESULT INLINE
  1563. CJoy_OpenIdSubkey(PDJ this, DWORD dwId, PHKEY phk)
  1564. {
  1565. return CType_OpenIdSubkey(this->hkType, dwId, KEY_QUERY_VALUE, phk);
  1566. }
  1567. /*****************************************************************************
  1568. *
  1569. * @doc INTERNAL
  1570. *
  1571. * @method HRESULT | CJoy | GetObjectInfo |
  1572. *
  1573. * Obtain the friendly name and FF/HID information
  1574. * of an object.
  1575. *
  1576. * @parm IN LPCDIPROPINFO | ppropi |
  1577. *
  1578. * Information describing the object being accessed.
  1579. *
  1580. * @parm IN OUT LPDIDEVICEOBJECTINSTANCEW | pdidioiW |
  1581. *
  1582. * Structure to receive information. The
  1583. * <e DIDEVICEOBJECTINSTANCE.guidType>,
  1584. * <e DIDEVICEOBJECTINSTANCE.dwOfs>,
  1585. * and
  1586. * <e DIDEVICEOBJECTINSTANCE.dwType>
  1587. * <e DIDEVICEOBJECTINSTANCE.dwFlags>
  1588. * fields have already been filled in.
  1589. *
  1590. * @returns
  1591. *
  1592. * Returns a COM error code.
  1593. *
  1594. *****************************************************************************/
  1595. STDMETHODIMP
  1596. CJoy_GetObjectInfo(PDICB pdcb, LPCDIPROPINFO ppropi,
  1597. LPDIDEVICEOBJECTINSTANCEW pdidoiW)
  1598. {
  1599. HRESULT hres;
  1600. PDJ this;
  1601. EnterProcI(IDirectInputDeviceCallback::Joy::GetObjectInfo,
  1602. (_ "pxp", pdcb, ppropi->iobj, pdidoiW));
  1603. /*
  1604. * This is an internal interface, so we can skimp on validation.
  1605. */
  1606. this = _thisPvNm(pdcb, dcb);
  1607. AssertF(IsValidSizeDIDEVICEOBJECTINSTANCEW(pdidoiW->dwSize));
  1608. if (ppropi->iobj < this->df.dwNumObjs) {
  1609. AssertF(ppropi->dwDevType == this->df.rgodf[ppropi->iobj].dwType);
  1610. CType_RegGetObjectInfo(this->hkType, ppropi->dwDevType, pdidoiW);
  1611. /*
  1612. * If we couldn't get a name from the registry,
  1613. * then grab one of the standard names.
  1614. */
  1615. if (pdidoiW->tszName[0] == L'\0') {
  1616. UINT dids;
  1617. if (ppropi->dwDevType & DIDFT_AXIS) {
  1618. dids = 0;
  1619. LoadStringW(g_hinst, IDS_JOYSTICKOBJECT + dids +
  1620. DIDFT_GETINSTANCE(ppropi->dwDevType),
  1621. pdidoiW->tszName, cA(pdidoiW->tszName));
  1622. } else if (ppropi->dwDevType & DIDFT_BUTTON) {
  1623. GetNthButtonString(pdidoiW->tszName,
  1624. DIDFT_GETINSTANCE(ppropi->dwDevType));
  1625. } else {
  1626. AssertF(ppropi->dwDevType & DIDFT_POV);
  1627. GetNthPOVString(pdidoiW->tszName,
  1628. DIDFT_GETINSTANCE(ppropi->dwDevType));
  1629. }
  1630. }
  1631. /*
  1632. * ISSUE-2001/03/29-timgill Need a faster way of checking VJoyD devices
  1633. * On Win9x, many HID devices cannot use our ring 3 HID path so try
  1634. * to get any axis or POV usage from VJoyD
  1635. * This is not cheap to get but until we have a better way to
  1636. * make sure the VJoyD device has not changed under us this is better
  1637. * than caching it. This is not inner loop code anyway.
  1638. */
  1639. #ifndef WINNT
  1640. if( pdidoiW->dwSize >= cbX(DIDEVICEOBJECTINSTANCE_DX5W) )
  1641. {
  1642. VXDINITPARMS vip;
  1643. hres = Hel_Joy_GetInitParms(this->idJoy, &vip);
  1644. if( SUCCEEDED( hres ) && ( vip.dwFlags & VIP_ISHID ) )
  1645. {
  1646. if( ppropi->dwDevType & DIDFT_AXIS )
  1647. {
  1648. int AxisIdx;
  1649. AxisIdx = c_rgiJoyPosAxisFromStateAxis[DIDFT_GETINSTANCE(ppropi->dwDevType)];
  1650. pdidoiW->wUsagePage = HIWORD( vip.Usages[AxisIdx] );
  1651. pdidoiW->wUsage = LOWORD( vip.Usages[AxisIdx] );
  1652. }
  1653. else if( ppropi->dwDevType & DIDFT_BUTTON )
  1654. {
  1655. /*
  1656. * Only JoyHID uses this interface and it only counts
  1657. * button page buttons so assume the simplest case.
  1658. */
  1659. pdidoiW->wUsagePage = HID_USAGE_PAGE_BUTTON;
  1660. pdidoiW->wUsage = 1 + DIDFT_GETINSTANCE( ppropi->dwDevType );
  1661. }
  1662. else
  1663. {
  1664. AssertF(ppropi->dwDevType & DIDFT_POV);
  1665. pdidoiW->wUsagePage = HIWORD( ((PDWORD)(&vip.dwPOV0usage))[DIDFT_GETINSTANCE(ppropi->dwDevType)] );
  1666. pdidoiW->wUsage = LOWORD( ((PDWORD)(&vip.dwPOV0usage))[DIDFT_GETINSTANCE(ppropi->dwDevType)] );
  1667. }
  1668. }
  1669. }
  1670. /*
  1671. * Ignore any errors getting params.
  1672. */
  1673. #endif
  1674. hres = S_OK;
  1675. } else {
  1676. hres = E_INVALIDARG;
  1677. }
  1678. ExitOleProcR();
  1679. return hres;
  1680. }
  1681. /*****************************************************************************
  1682. *
  1683. * @doc INTERNAL
  1684. *
  1685. * @method HRESULT | CJoy | SetCooperativeLevel |
  1686. *
  1687. * The app changed the cooperative level.
  1688. * Un-subclass the old window and en-subclass the new window.
  1689. *
  1690. * @parm IN HWND | hwnd |
  1691. *
  1692. * The window handle.
  1693. *
  1694. * @parm IN DWORD | dwFlags |
  1695. *
  1696. * The cooperativity level.
  1697. *
  1698. *****************************************************************************/
  1699. STDMETHODIMP
  1700. CJoy_SetCooperativeLevel(PDICB pdcb, HWND hwnd, DWORD dwFlags)
  1701. {
  1702. HRESULT hres;
  1703. PDJ this;
  1704. EnterProcI(IDirectInputDeviceCallback::Joy::SetCooperativityLevel,
  1705. (_ "pxx", pdcb, hwnd, dwFlags));
  1706. /*
  1707. * This is an internal interface, so we can skimp on validation.
  1708. */
  1709. this = _thisPvNm(pdcb, dcb);
  1710. /*
  1711. * First get out of the old window.
  1712. */
  1713. CJoy_RemoveSubclass(this);
  1714. /*
  1715. * Prefix warns that "this" may have been freed (mb:34574) however
  1716. * If you're in SetCooperativeLevel and you have a window subclassed
  1717. * then there must be a hold for the subclassed window as well as
  1718. * one for the unreleased interface so the Common_Unhold won't free
  1719. * the pointer.
  1720. */
  1721. /*
  1722. * If a new window is passed, then subclass it so we can
  1723. * watch for joystick configuration change messages.
  1724. *
  1725. * If we can't, don't worry. All it means that we won't
  1726. * be able to catch when the user recalibrates the joystick,
  1727. * which isn't very often.
  1728. */
  1729. if (hwnd) {
  1730. if (SetWindowSubclass(hwnd, CJoy_SubclassProc, 0, (ULONG_PTR)this)) {
  1731. this->hwnd = hwnd;
  1732. Common_Hold(this);
  1733. }
  1734. } else {
  1735. RPF("SetCooperativeLevel: You really shouldn't pass hwnd = 0; "
  1736. "joystick calibration may be dodgy");
  1737. }
  1738. hres = S_OK;
  1739. ExitOleProcR();
  1740. return hres;
  1741. }
  1742. /*****************************************************************************
  1743. *
  1744. * @doc INTERNAL
  1745. *
  1746. * @method HRESULT | CJoy | RunControlPanel |
  1747. *
  1748. * Run the joystick control panel.
  1749. *
  1750. * @parm IN HWND | hwndOwner |
  1751. *
  1752. * The owner window.
  1753. *
  1754. * @parm DWORD | dwFlags |
  1755. *
  1756. * Flags.
  1757. *
  1758. *****************************************************************************/
  1759. TCHAR c_tszJoyCpl[] = TEXT("joy.cpl");
  1760. STDMETHODIMP
  1761. CJoy_RunControlPanel(PDICB pdcb, HWND hwnd, DWORD dwFlags)
  1762. {
  1763. HRESULT hres;
  1764. PDJ this;
  1765. EnterProcI(IDirectInputDeviceCallback::Joy::RunControlPanel,
  1766. (_ "pxx", pdcb, hwnd, dwFlags));
  1767. /*
  1768. * This is an internal interface, so we can skimp on validation.
  1769. */
  1770. this = _thisPvNm(pdcb, dcb);
  1771. hres = hresRunControlPanel(c_tszJoyCpl);
  1772. ExitOleProcR();
  1773. return hres;
  1774. }
  1775. /*****************************************************************************
  1776. *
  1777. * @doc INTERNAL
  1778. *
  1779. * @method HRESULT | CJoy | GetFFConfigKey |
  1780. *
  1781. * Open and return the registry key that contains
  1782. * force feedback configuration information.
  1783. *
  1784. * @parm DWORD | sam |
  1785. *
  1786. * Security access mask.
  1787. *
  1788. * @parm PHKEY | phk |
  1789. *
  1790. * Receives the registry key.
  1791. *
  1792. *****************************************************************************/
  1793. STDMETHODIMP
  1794. CJoy_GetFFConfigKey(PDICB pdcb, DWORD sam, PHKEY phk)
  1795. {
  1796. HRESULT hres;
  1797. PDJ this;
  1798. EnterProcI(IDirectInputDeviceCallback::Joy::GetFFConfigKey,
  1799. (_ "px", pdcb, sam));
  1800. /*
  1801. * This is an internal interface, so we can skimp on validation.
  1802. */
  1803. this = _thisPvNm(pdcb, dcb);
  1804. hres = JoyReg_OpenFFKey(this->hkType, sam, phk);
  1805. AssertF(fLeqvFF(SUCCEEDED(hres), *phk));
  1806. ExitBenignOleProcPpvR(phk);
  1807. return hres;
  1808. }
  1809. /*****************************************************************************
  1810. *
  1811. * @doc INTERNAL
  1812. *
  1813. * @method HRESULT | CJoy | CreateEffect |
  1814. *
  1815. * Create an <i IDirectInputEffectDriver> interface.
  1816. *
  1817. * @parm LPDIRECTINPUTEFFECTSHEPHERD * | ppes |
  1818. *
  1819. * Receives the shepherd for the effect driver.
  1820. *
  1821. *****************************************************************************/
  1822. STDMETHODIMP
  1823. CJoy_CreateEffect(PDICB pdcb, LPDIRECTINPUTEFFECTSHEPHERD *ppes)
  1824. {
  1825. HRESULT hres;
  1826. PDJ this;
  1827. HKEY hk;
  1828. EnterProcI(IDirectInputDeviceCallback::Joy::CreateEffect, (_ "p", pdcb));
  1829. /*
  1830. * This is an internal interface, so we can skimp on validation.
  1831. */
  1832. this = _thisPvNm(pdcb, dcb);
  1833. hres = CJoy_GetFFConfigKey(pdcb, KEY_QUERY_VALUE, &hk);
  1834. if (SUCCEEDED(hres)) {
  1835. hres = CEShep_New(hk, 0, &IID_IDirectInputEffectShepherd, ppes);
  1836. if (SUCCEEDED(hres)) {
  1837. #ifndef WINNT
  1838. VXDINITPARMS vip;
  1839. CHAR szPath[MAX_PATH];
  1840. PCHAR pszPath;
  1841. pszPath = JoyReg_JoyIdToDeviceInterface_95( this->idJoy, &vip, szPath );
  1842. if( pszPath )
  1843. {
  1844. DIHIDFFINITINFO init;
  1845. WCHAR wszPath[MAX_PATH];
  1846. ZeroX(init);
  1847. init.dwSize = cbX(init);
  1848. TToU( wszPath, cA(wszPath), pszPath );
  1849. init.pwszDeviceInterface = wszPath;
  1850. hresFindHIDDeviceInterface(pszPath, &init.GuidInstance);
  1851. hres = (*ppes)->lpVtbl->DeviceID((*ppes), this->idJoy, TRUE, &init);
  1852. }
  1853. else
  1854. #endif
  1855. {
  1856. hres = (*ppes)->lpVtbl->DeviceID((*ppes), this->idJoy, TRUE, 0);
  1857. }
  1858. }
  1859. if (SUCCEEDED(hres)) {
  1860. } else {
  1861. Invoke_Release(ppes);
  1862. }
  1863. RegCloseKey(hk);
  1864. } else {
  1865. hres = E_NOTIMPL;
  1866. *ppes = 0;
  1867. }
  1868. ExitOleProcPpvR(ppes);
  1869. return hres;
  1870. }
  1871. /*****************************************************************************
  1872. *
  1873. * @doc INTERNAL
  1874. *
  1875. * @method HRESULT | CJoy | GetVersions |
  1876. *
  1877. * Ping down into the driver to get the driver version info.
  1878. *
  1879. * @parm LPDIDRIVERVERSIONS | pvers |
  1880. *
  1881. * A structure which should be filled in with version information
  1882. * describing the hardware, firmware, and driver.
  1883. *
  1884. * DirectInput will set the <e DIDRIVERVERSIONS.dwSize> field
  1885. * to sizeof(DIDRIVERVERSIONS) before calling this method.
  1886. *
  1887. * @returns
  1888. *
  1889. * <c S_OK> if we succeeded.
  1890. *
  1891. *****************************************************************************/
  1892. STDMETHODIMP
  1893. CJoy_GetVersions(PDICB pdcb, LPDIDRIVERVERSIONS pvers)
  1894. {
  1895. HRESULT hres;
  1896. PDJ this;
  1897. VXDINITPARMS vip;
  1898. EnterProcI(IDirectInputDeviceCallback::Joy::GetVersions, (_ "p", pdcb));
  1899. /*
  1900. * This is an internal interface, so we can skimp on validation.
  1901. */
  1902. this = _thisPvNm(pdcb, dcb);
  1903. AssertF(pvers->dwSize == cbX(*pvers));
  1904. hres = Hel_Joy_GetInitParms(this->idJoy, &vip);
  1905. if (SUCCEEDED(hres)) {
  1906. pvers->dwFirmwareRevision = vip.dwFirmwareRevision;
  1907. pvers->dwHardwareRevision = vip.dwHardwareRevision;
  1908. pvers->dwFFDriverVersion = vip.dwFFDriverVersion;
  1909. }
  1910. return hres;
  1911. }
  1912. /*****************************************************************************
  1913. *
  1914. * Joystick registry usage
  1915. *
  1916. *****************************************************************************
  1917. *
  1918. * Global joystick information is kept under
  1919. *
  1920. * HKEY_LOCAL_MACHINE\
  1921. * System\
  1922. * CurrentControlSet\
  1923. * Control\
  1924. * MediaProperties\
  1925. * Joystick\
  1926. * OEM
  1927. *
  1928. * Under this key is a number of subkeys, each corresponding to a brand
  1929. * of joystick.
  1930. *
  1931. * Under each OEM\<name> key, you can find the following values:
  1932. *
  1933. * OEMData
  1934. *
  1935. * This is a binary value containing a structure of two dwords.
  1936. * The first is the JOYREGHWCONFIG.hws.dwFlags and the second
  1937. * is the JOYREGHWCONFIG.hws.dwNumButtons.
  1938. *
  1939. * OEMName
  1940. *
  1941. * This is a string which gives a friendly name for the unit.
  1942. *
  1943. *
  1944. *****************************************************************************
  1945. *
  1946. * Under the driver key is kept information about the particular joystick.
  1947. *
  1948. * HKEY_LOCAL_MACHINE\
  1949. * System\
  1950. * CurrentControlSet\
  1951. * Control\
  1952. * MediaResources\
  1953. * Joystick\
  1954. * <driver key name>\
  1955. * CurrentJoystickSettings
  1956. *
  1957. * Under this key, there are a bunch of values named
  1958. * Joystick##Configuration, where ## is the joystick number
  1959. * (1 through 16). Each value contains binary data in the form
  1960. * of a JOYREGHWCONFIG, which looks like this:
  1961. *
  1962. * DWORD hws.dwFlags; // JOY_HWS_* \
  1963. * DWORD hws.dwNumButtons; _\ JOYREGHWSETTINGS
  1964. * DWORD dwUsageSettings;// JOY_US_* _____
  1965. * DWORD hwv.jrvHardware.jpMin.dwX; \ |
  1966. * DWORD hwv.jrvHardware.jpMin.dwY; \ |
  1967. * DWORD hwv.jrvHardware.jpMin.dwZ; \
  1968. * DWORD hwv.jrvHardware.jpMin.dwR; |
  1969. * DWORD hwv.jrvHardware.jpMin.dwU; > JOYREGHWVALUES.JOYRANGE
  1970. * DWORD hwv.jrvHardware.jpMin.dwV; |
  1971. * DWORD hwv.jrvHardware.jpMax.dwX; | |
  1972. * DWORD hwv.jrvHardware.jpMax.dwY; | |
  1973. * DWORD hwv.jrvHardware.jpMax.dwZ; | \
  1974. * DWORD hwv.jrvHardware.jpMax.dwR; | > JOYREGHWVALUES
  1975. * DWORD hwv.jrvHardware.jpMax.dwU; | /
  1976. * DWORD hwv.jrvHardware.jpMax.dwV; | |
  1977. * DWORD hwv.jrvHardware.jpCenter.dwX; | |
  1978. * DWORD hwv.jrvHardware.jpCenter.dwY; | |
  1979. * DWORD hwv.jrvHardware.jpCenter.dwZ; | |
  1980. * DWORD hwv.jrvHardware.jpCenter.dwR; / |
  1981. * DWORD hwv.jrvHardware.jpCenter.dwU; / |
  1982. * DWORD hwv.jrvHardware.jpCenter.dwV; / |
  1983. * DWORD hwv.dwPOVValues[4]; |
  1984. * DWORD hwv.dwCalFlags; ______|
  1985. * DWORD dwType; // JOY_HW_*
  1986. * DWORD dwReserved;
  1987. *
  1988. *
  1989. * Also under this key are optional values named Joystick##OEMName.
  1990. * If present, it is a string-data key whose contents are the name
  1991. * of another key that describes the joystick, stored in the global
  1992. * section described above.
  1993. *
  1994. * Meanwhile, under the key
  1995. *
  1996. * HKEY_LOCAL_MACHINE\
  1997. * System\
  1998. * CurrentControlSet\
  1999. * Control\
  2000. * MediaResources\
  2001. * Joystick\
  2002. * <driver key name>
  2003. *
  2004. * is a value called "JoystickUserValues". This is a binary key
  2005. * that contains a JOYREGUSERVALUES structure:
  2006. *
  2007. * DWORD dwTimeOut;
  2008. * DWORD jrvRanges.jpMin.dwX; \
  2009. * DWORD jrvRanges.jpMin.dwY; \
  2010. * DWORD jrvRanges.jpMin.dwZ; \
  2011. * DWORD jrvRanges.jpMin.dwR; |
  2012. * DWORD jrvRanges.jpMin.dwU; > JOYRANGE
  2013. * DWORD jrvRanges.jpMin.dwV; |
  2014. * DWORD jrvRanges.jpMax.dwX; |
  2015. * DWORD jrvRanges.jpMax.dwY; |
  2016. * DWORD jrvRanges.jpMax.dwZ; |
  2017. * DWORD jrvRanges.jpMax.dwR; |
  2018. * DWORD jrvRanges.jpMax.dwU; |
  2019. * DWORD jrvRanges.jpMax.dwV; |
  2020. * DWORD jrvRanges.jpCenter.dwX; | (ignored)
  2021. * DWORD jrvRanges.jpCenter.dwY; | (ignored)
  2022. * DWORD jrvRanges.jpCenter.dwZ; | (ignored)
  2023. * DWORD jrvRanges.jpCenter.dwR; / (ignored)
  2024. * DWORD jrvRanges.jpCenter.dwU; / (ignored)
  2025. * DWORD jrvRanges.jpCenter.dwV; / (ignored)
  2026. * DWORD jpDeadZone.dwX; \
  2027. * DWORD jpDeadZone.dwY; \
  2028. * DWORD jpDeadZone.dwZ; \ JOYPOS
  2029. * DWORD jpDeadZone.dwR; / Dead zone is recorded as a
  2030. * DWORD jpDeadZone.dwU; / percentage of total range
  2031. * DWORD jpDeadZone.dwV; /
  2032. *
  2033. * If there is no JoystickUserValues, then the following defaults
  2034. * are used:
  2035. *
  2036. * jpMin.dw# = 0;
  2037. * jpMax.dw# = 65535;
  2038. * jpCenter.dw# = jpMax.dw# / 2;
  2039. * jrvDeadZone.dw# = 5;
  2040. *
  2041. * (See ibmjoy\msjstick.c, function jsReadRegistry for the code that
  2042. * sets the defaults.)
  2043. *
  2044. * We will also use the defaults if Min > Max or if Max >= 0x80000000
  2045. * or if DeadZone > 100.
  2046. *
  2047. *****************************************************************************/
  2048. /*****************************************************************************
  2049. *
  2050. * @doc INTERNAL
  2051. *
  2052. * @method void | CJoy | InitPhysRanges |
  2053. *
  2054. * Initialize (or re-initialize)
  2055. * the physical min/max/center values. This is
  2056. * done as part of device initialization as well as in response
  2057. * to a notification that the Joystick control panel has been
  2058. * dinked with.
  2059. *
  2060. * It is assumed that the <e DJ.hwc> already contains the
  2061. * registry hardware settings.
  2062. *
  2063. * After the phys ranges are set, the ramps are recalculated.
  2064. *
  2065. *
  2066. *****************************************************************************/
  2067. void INTERNAL
  2068. CJoy_InitPhysRanges(PDJ this, LPJOYREGHWCONFIG phwc)
  2069. {
  2070. UINT uiPosAxis;
  2071. UINT uiStateAxis;
  2072. #define GetJoyPosValue(phwc, f, i) \
  2073. *(LPDWORD)pvAddPvCb(&phwc->hwv.jrvHardware.f, \
  2074. ibJoyPosAxisFromPosAxis(i)) \
  2075. for (uiPosAxis = 0; uiPosAxis < cJoyPosAxisMax; uiPosAxis++) {
  2076. DWORD dwMax, dwC;
  2077. PJOYRANGECONVERT pjrc;
  2078. uiStateAxis = iJoyStateAxisFromPosAxis(uiPosAxis);
  2079. pjrc = &this->rgjrc[uiStateAxis];
  2080. pjrc->dwPmin = GetJoyPosValue(phwc, jpMin, uiPosAxis);
  2081. /*
  2082. * HACKHACK - Uncalibrated joysticks will have max == 0, in which
  2083. * case we use a fake max of 655, just like VJOYD.
  2084. */
  2085. dwMax = GetJoyPosValue(phwc, jpMax, uiPosAxis);
  2086. if (dwMax == 0) {
  2087. dwMax = 655;
  2088. }
  2089. pjrc->dwPmax = dwMax;
  2090. /*
  2091. * HACKHACK - Uncalibrated joysticks will have center == 0,
  2092. * in which case we use a fake center of midway between min and
  2093. * max, just like VJOYD.
  2094. *
  2095. * Quirk - Z, R, U, and V typically are not center-calibrated,
  2096. * so if the jpCenter value is not strictly between min and
  2097. * max, then assume it's one of the bogus cases and slam it
  2098. * into the middle of the range.
  2099. */
  2100. dwC = GetJoyPosValue(phwc, jpCenter, uiPosAxis);
  2101. if (dwC <= pjrc->dwPmin || dwC >= pjrc->dwPmax) {
  2102. dwC = (pjrc->dwPmin + pjrc->dwPmax) / 2;
  2103. }
  2104. pjrc->dwPc = dwC;
  2105. if( pjrc->dwCPointsNum == 0 ) {
  2106. //use two control points by default
  2107. pjrc->dwCPointsNum = 2;
  2108. pjrc->cp[0].lP = pjrc->dwPmin;
  2109. pjrc->cp[0].dwLog = 0;
  2110. pjrc->cp[1].lP = pjrc->dwPmax;
  2111. pjrc->cp[1].dwLog = RANGEDIVISIONS;
  2112. } else {
  2113. pjrc->cp[0].lP = pjrc->dwPmin;
  2114. pjrc->cp[pjrc->dwCPointsNum-1].lP = pjrc->dwPmax;
  2115. }
  2116. SquirtSqflPtszV(sqfl,
  2117. TEXT("CJoy_PhysRange %d -> %d: %08x / %08x / %08x"),
  2118. uiPosAxis,
  2119. uiStateAxis,
  2120. pjrc->dwPmin,
  2121. pjrc->dwPc,
  2122. pjrc->dwPmax);
  2123. }
  2124. #undef GetJoyValue
  2125. /*
  2126. * These two phantom axes are always raw because they don't exist.
  2127. */
  2128. this->rgjrc[iJoyStateAxisRx].fRaw = TRUE;
  2129. this->rgjrc[iJoyStateAxisRy].fRaw = TRUE;
  2130. /*
  2131. * Now compute all the dependent variables.
  2132. */
  2133. for (uiStateAxis = 0; uiStateAxis < cA(this->rgjrc); uiStateAxis++) {
  2134. CCal_RecalcRange(&this->rgjrc[uiStateAxis]);
  2135. }
  2136. }
  2137. /*****************************************************************************
  2138. *
  2139. * @doc INTERNAL
  2140. *
  2141. * @method void | CJoy | InitLogRanges |
  2142. *
  2143. * Initialize the logical ranges from the user values.
  2144. *
  2145. *****************************************************************************/
  2146. void INLINE
  2147. CJoy_InitLogRanges(PDJ this)
  2148. {
  2149. HRESULT hres;
  2150. UINT uiPosAxis;
  2151. UINT uiStateAxis;
  2152. DIJOYUSERVALUES juv;
  2153. hres = JoyReg_GetUserValues(&juv, DIJU_USERVALUES);
  2154. AssertF(SUCCEEDED(hres));
  2155. #define pJoyValue(jp, i) \
  2156. (LPDWORD)pvAddPvCb(&(jp), ibJoyPosAxisFromPosAxis(i)) \
  2157. for (uiPosAxis = 0; uiPosAxis < cJoyPosAxisMax; uiPosAxis++) {
  2158. PJOYRANGECONVERT pjrc;
  2159. AssertF((int)*pJoyValue(juv.ruv.jrvRanges.jpMax, uiPosAxis) >= 0);
  2160. AssertF(*pJoyValue(juv.ruv.jrvRanges.jpMin, uiPosAxis) <
  2161. *pJoyValue(juv.ruv.jrvRanges.jpMax, uiPosAxis));
  2162. uiStateAxis = iJoyStateAxisFromPosAxis(uiPosAxis);
  2163. pjrc = &this->rgjrc[uiStateAxis];
  2164. pjrc->lMin = *pJoyValue(juv.ruv.jrvRanges.jpMin, uiPosAxis);
  2165. pjrc->lMax = *pJoyValue(juv.ruv.jrvRanges.jpMax, uiPosAxis);
  2166. /*
  2167. * Note that we do *not* use the jpCenter value. Strange
  2168. * but true.
  2169. *
  2170. * The sum cannot overflow due to the sanity checks we did above.
  2171. */
  2172. pjrc->lC = CCal_Midpoint(pjrc->lMin, pjrc->lMax);
  2173. /*
  2174. * Now do the dead zone. Convert from percent to range units.
  2175. */
  2176. pjrc->dwDz = *pJoyValue(juv.ruv.jpDeadZone, uiPosAxis) *
  2177. (RANGEDIVISIONS / 100);
  2178. if (pjrc->dwDz > RANGEDIVISIONS) {
  2179. pjrc->dwDz = 5 * (RANGEDIVISIONS / 100);
  2180. }
  2181. /*
  2182. * Now do the saturation level. It always defaults to 100%.
  2183. */
  2184. pjrc->dwSat = RANGEDIVISIONS;
  2185. }
  2186. }
  2187. #undef pJoyValue
  2188. /*****************************************************************************
  2189. *
  2190. * @doc INTERNAL
  2191. *
  2192. * @method void | CJoy | BuildAxes |
  2193. *
  2194. * Study a single capabilities flag and add axis items to the data
  2195. * format accordingly.
  2196. *
  2197. * @parm DWORD | dwCaps |
  2198. *
  2199. * Collection of <c JOYPF_*> flags describing the axes supported.
  2200. *
  2201. * @parm UINT | ib |
  2202. *
  2203. * Data format offset at which this data is provided.
  2204. *
  2205. * @parm UINT | uiObj |
  2206. *
  2207. * Instance index for the first item.
  2208. *
  2209. * @parm DWORD | dwAspect |
  2210. *
  2211. * <c DIDOI_ASPECT*> for these axes.
  2212. *
  2213. *****************************************************************************/
  2214. typedef struct AXISATTRIBUTES {
  2215. DWORD dwMask; /* Mask that identifies the axis */
  2216. UINT uidObj; /* Object index delta from X axis */
  2217. } AXISATTRIBUTES, *PAXISATTRIBUTES;
  2218. typedef const AXISATTRIBUTES *PCAXISATTRIBUTES;
  2219. typedef struct AXISMAPPINGS {
  2220. PCGUID pguid; /* GUID for the object */
  2221. DWORD dwSemantic; /* Default semantic map */
  2222. } AXISMAPPINGS, *PAXISMAPPINGS;
  2223. typedef const AXISMAPPINGS *PCAXISMAPPINGS;
  2224. const AXISATTRIBUTES c_rgaattrJoy[] = {
  2225. { JOYPF_X, iJoyStateAxisX, },
  2226. { JOYPF_Y, iJoyStateAxisY, },
  2227. { JOYPF_Z, iJoyStateAxisZ, },
  2228. { JOYPF_R, iJoyStateAxisRz, },
  2229. { JOYPF_U, iJoyStateAxisS0, },
  2230. { JOYPF_V, iJoyStateAxisS1, },
  2231. };
  2232. const AXISMAPPINGS c_rgamapJoy[6] = {
  2233. { &GUID_XAxis, DISEM_FLAGS_X | DISEM_TYPE_AXIS },
  2234. { &GUID_YAxis, DISEM_FLAGS_Y | DISEM_TYPE_AXIS },
  2235. { &GUID_Slider, DISEM_FLAGS_S | DISEM_TYPE_AXIS },
  2236. { &GUID_RzAxis, DISEM_FLAGS_R | DISEM_TYPE_AXIS },
  2237. { &GUID_Slider, DISEM_FLAGS_S | DISEM_TYPE_AXIS },
  2238. { &GUID_Slider, DISEM_FLAGS_S | DISEM_TYPE_AXIS },
  2239. };
  2240. const AXISMAPPINGS c_rgamap6DOF[6] = {
  2241. { &GUID_XAxis, DISEM_FLAGS_X | DISEM_TYPE_AXIS },
  2242. { &GUID_YAxis, DISEM_FLAGS_Y | DISEM_TYPE_AXIS },
  2243. { &GUID_ZAxis, DISEM_FLAGS_Z | DISEM_TYPE_AXIS },
  2244. { &GUID_RzAxis, DISEM_FLAGS_R | DISEM_TYPE_AXIS },
  2245. { &GUID_RyAxis, DISEM_FLAGS_U | DISEM_TYPE_AXIS },
  2246. { &GUID_RxAxis, DISEM_FLAGS_V | DISEM_TYPE_AXIS },
  2247. };
  2248. const AXISMAPPINGS c_rgamapZJoy[6] = {
  2249. { &GUID_XAxis, DISEM_FLAGS_X | DISEM_TYPE_AXIS },
  2250. { &GUID_YAxis, DISEM_FLAGS_Y | DISEM_TYPE_AXIS },
  2251. { &GUID_ZAxis, DISEM_FLAGS_Z | DISEM_TYPE_AXIS },
  2252. { &GUID_RzAxis, DISEM_FLAGS_R | DISEM_TYPE_AXIS },
  2253. { &GUID_Slider, DISEM_FLAGS_S | DISEM_TYPE_AXIS },
  2254. { &GUID_Slider, DISEM_FLAGS_S | DISEM_TYPE_AXIS },
  2255. };
  2256. /*
  2257. * Since default HID mapping maps accel to Y and brake to Rz
  2258. * use the GUIDs to match the correct axis to those mappings
  2259. * and set appropriate semantics.
  2260. */
  2261. const AXISMAPPINGS c_rgamapCarZY[6] = {
  2262. { &GUID_XAxis, DISEM_FLAGS_X | DISEM_TYPE_AXIS },
  2263. { &GUID_RzAxis, DISEM_FLAGS_B | DISEM_TYPE_AXIS },
  2264. { &GUID_YAxis, DISEM_FLAGS_A | DISEM_TYPE_AXIS },
  2265. { &GUID_Slider, DISEM_FLAGS_S | DISEM_TYPE_AXIS },
  2266. { &GUID_Slider, DISEM_FLAGS_S | DISEM_TYPE_AXIS },
  2267. { &GUID_Slider, DISEM_FLAGS_S | DISEM_TYPE_AXIS },
  2268. };
  2269. const AXISMAPPINGS c_rgamapCarYR[6] = {
  2270. { &GUID_XAxis, DISEM_FLAGS_X | DISEM_TYPE_AXIS },
  2271. { &GUID_YAxis, DISEM_FLAGS_A | DISEM_TYPE_AXIS },
  2272. { &GUID_ZAxis, DISEM_FLAGS_Z | DISEM_TYPE_AXIS },
  2273. { &GUID_RzAxis, DISEM_FLAGS_B | DISEM_TYPE_AXIS },
  2274. { &GUID_Slider, DISEM_FLAGS_S | DISEM_TYPE_AXIS },
  2275. { &GUID_Slider, DISEM_FLAGS_S | DISEM_TYPE_AXIS },
  2276. };
  2277. const AXISMAPPINGS c_rgamapCarZR[6] = {
  2278. { &GUID_XAxis, DISEM_FLAGS_X | DISEM_TYPE_AXIS },
  2279. { &GUID_Slider, DISEM_FLAGS_S | DISEM_TYPE_AXIS },
  2280. { &GUID_YAxis, DISEM_FLAGS_A | DISEM_TYPE_AXIS },
  2281. { &GUID_RzAxis, DISEM_FLAGS_B | DISEM_TYPE_AXIS },
  2282. { &GUID_Slider, DISEM_FLAGS_S | DISEM_TYPE_AXIS },
  2283. { &GUID_Slider, DISEM_FLAGS_S | DISEM_TYPE_AXIS },
  2284. };
  2285. /*****************************************************************************
  2286. *
  2287. * @doc INTERNAL
  2288. *
  2289. * @method HRESULT | CJoy | InitFromHwc |
  2290. *
  2291. * Initialize the information that is kept in the
  2292. * <t JOYREGHWCONFIG>.
  2293. *
  2294. * Broken out from CJoy_InitRing3 to make things less monolithic.
  2295. *
  2296. * The <e CJoy.cfg> structure already contains joystick
  2297. * configuration information.
  2298. *
  2299. *****************************************************************************/
  2300. HRESULT INLINE
  2301. CJoy_InitFromHwc(PDJ this)
  2302. {
  2303. HRESULT hres;
  2304. DWORD dwTestType;
  2305. if( this->cfg.hwc.dwType >= JOY_HW_PREDEFMIN && this->cfg.hwc.dwType < JOY_HW_PREDEFMAX ) {
  2306. WCHAR wszType[4];
  2307. wszType[0] = L'#';
  2308. wszType[1] = L'0' + (WCHAR)this->cfg.hwc.dwType;
  2309. wszType[2] = L'\0';
  2310. hres = JoyReg_GetPredefTypeInfo( wszType, &this->typi, DITC_DISPLAYNAME);
  2311. } else if (this->cfg.wszType[0] != L'\0' ) {
  2312. hres = JoyReg_GetTypeInfo(this->cfg.wszType, &this->typi, DITC_DISPLAYNAME | DITC_FLAGS2 );
  2313. if (SUCCEEDED(hres)) {
  2314. } else {
  2315. #ifdef WINNT
  2316. ZeroMemory(&this->typi, cbX(this->typi));
  2317. #else
  2318. //lstrcpyW( this->typi.wszDisplayName, this->cfg.wszType );
  2319. memset( &this->typi.wszDisplayName[0], 0, sizeof(this->typi.wszDisplayName) );
  2320. memcpy( &this->typi.wszDisplayName[0], &this->cfg.wszType[0], sizeof(this->cfg.wszType));
  2321. #endif
  2322. }
  2323. } else {
  2324. ZeroMemory(&this->typi, cbX(this->typi));
  2325. }
  2326. #define hwc this->cfg.hwc
  2327. if( ( this->typi.dwFlags2 & ( JOYTYPE_HIDEACTIVE | JOYTYPE_GAMEHIDE ) )
  2328. == ( JOYTYPE_HIDEACTIVE | JOYTYPE_GAMEHIDE ) )
  2329. {
  2330. this->dc.dwFlags |= DIDC_HIDDEN;
  2331. }
  2332. dwTestType = GetValidDI8DevType( this->typi.dwFlags2, this->dc.dwButtons, hwc.hws.dwFlags );
  2333. if( dwTestType )
  2334. {
  2335. /*
  2336. * If a valid override exists just use it
  2337. */
  2338. this->dc.dwDevType = dwTestType;
  2339. }
  2340. else
  2341. {
  2342. #ifdef XDEBUG
  2343. if( GET_DIDEVICE_TYPEANDSUBTYPE( this->typi.dwFlags2 ) )
  2344. {
  2345. RPF( "Ignoring invalid type/subtype Flags2 value 0x%08x for joystick", this->typi.dwFlags2 );
  2346. }
  2347. #endif
  2348. if (hwc.hws.dwFlags & JOY_HWS_ISYOKE)
  2349. {
  2350. dwTestType = MAKE_DIDEVICE_TYPE(DI8DEVTYPE_FLIGHT, DI8DEVTYPEFLIGHT_STICK);
  2351. }
  2352. else if (hwc.hws.dwFlags & JOY_HWS_ISGAMEPAD)
  2353. {
  2354. dwTestType = MAKE_DIDEVICE_TYPE(DI8DEVTYPE_GAMEPAD, DI8DEVTYPEGAMEPAD_STANDARD);
  2355. }
  2356. else if (hwc.hws.dwFlags & JOY_HWS_ISCARCTRL)
  2357. {
  2358. AssertF( this->dc.dwAxes > 1 );
  2359. if ( this->dc.dwAxes <= 2 )
  2360. {
  2361. dwTestType = MAKE_DIDEVICE_TYPE(DI8DEVTYPE_DRIVING, DI8DEVTYPEDRIVING_COMBINEDPEDALS );
  2362. }
  2363. else
  2364. {
  2365. dwTestType = MAKE_DIDEVICE_TYPE(DI8DEVTYPE_DRIVING, DI8DEVTYPEDRIVING_DUALPEDALS );
  2366. }
  2367. }
  2368. else if (hwc.hws.dwFlags & JOY_HWS_ISHEADTRACKER)
  2369. {
  2370. dwTestType = MAKE_DIDEVICE_TYPE(DI8DEVTYPE_SUPPLEMENTAL, DI8DEVTYPESUPPLEMENTAL_HEADTRACKER);
  2371. }
  2372. else
  2373. {
  2374. dwTestType = MAKE_DIDEVICE_TYPE(DI8DEVTYPE_JOYSTICK, DI8DEVTYPEJOYSTICK_STANDARD);
  2375. }
  2376. /*
  2377. * Use the common function to make this a limited type if the
  2378. * number of buttons or flags dictate it.
  2379. * Since the type and subtype are known to be valid, the return
  2380. * value should never be a failure (zero).
  2381. */
  2382. this->dc.dwDevType = GetValidDI8DevType( dwTestType, this->dc.dwButtons, hwc.hws.dwFlags );
  2383. AssertF( this->dc.dwDevType );
  2384. }
  2385. #undef hwc
  2386. /*
  2387. * Now that we know the type, then make up a name ourselves if we
  2388. * previously failed to do so.
  2389. */
  2390. if (this->typi.wszDisplayName[0] == TEXT('\0'))
  2391. {
  2392. CType_MakeGameCtrlName( this->typi.wszDisplayName,
  2393. this->dc.dwDevType, this->dc.dwAxes, this->dc.dwButtons, this->dc.dwPOVs );
  2394. }
  2395. hres = S_OK;
  2396. return hres;
  2397. }
  2398. /*****************************************************************************
  2399. *
  2400. * @doc INTERNAL
  2401. *
  2402. * @method void | CJoy | AddObject |
  2403. *
  2404. * Add one object to the device format.
  2405. *
  2406. * If the device is polled, then the object is polled, too.
  2407. *
  2408. * @cwrap PDJ | this
  2409. *
  2410. * @parm PCGUID | pguid |
  2411. *
  2412. * The <t GUID> that classifies the device.
  2413. *
  2414. * @parm DWORD | dwOfs |
  2415. *
  2416. * Data offset.
  2417. *
  2418. * @parm DWORD | dwDevType |
  2419. *
  2420. * Device type flags to apply to the object.
  2421. *
  2422. * @parm UINT | uiObj |
  2423. *
  2424. * Object instance number.
  2425. *
  2426. * @parm DWORD | dwAspect |
  2427. *
  2428. * Optional <c DIDOI_ASPECT*> flag.
  2429. *
  2430. *****************************************************************************/
  2431. void INTERNAL
  2432. CJoy_AddObject(PDJ this, PCGUID pguid, DWORD dwOfs,
  2433. DWORD dwDevType, UINT uiObj, DWORD dwAspect, BOOL fReal)
  2434. {
  2435. LPDIOBJECTDATAFORMAT podf;
  2436. podf = &this->df.rgodf[this->df.dwNumObjs++];
  2437. podf->pguid = pguid;
  2438. podf->dwOfs = dwOfs;
  2439. podf->dwType = dwDevType | DIDFT_MAKEINSTANCE(uiObj);
  2440. podf->dwFlags = dwAspect;
  2441. if (this->dc.dwFlags & DIDC_POLLEDDEVICE) {
  2442. podf->dwFlags |= DIDOI_POLLED;
  2443. }
  2444. if( fReal )
  2445. {
  2446. CType_RegGetTypeInfo(this->hkType, podf, FALSE);
  2447. if( ( GET_DIDEVICE_TYPE( this->dc.dwDevType ) == DI8DEVTYPE_DRIVING )
  2448. && ( podf->dwFlags & DIDOI_FFACTUATOR )
  2449. && ( podf->pguid != &GUID_XAxis ) )
  2450. {
  2451. /*
  2452. * IHVs set FF attributes on non-FF axes for wheels because
  2453. * first generation FF apps were only written to support joysticks.
  2454. * Since we now munge the various configurations of pedal axes to
  2455. * report all split pedals in the same way, the fake Y axis can
  2456. * land up on different axes, usually Slider0. Rather than have
  2457. * people code to these different fake axes, strip out actuator
  2458. * status from any driving axis except the wheel.
  2459. */
  2460. podf->dwFlags &= ~DIDOI_FFACTUATOR;
  2461. podf->dwType &= ~DIDFT_FFACTUATOR;
  2462. }
  2463. }
  2464. }
  2465. void INTERNAL
  2466. CJoy_BuildAxes(PDJ this, DWORD dwCaps, UINT ib, UINT uiObj,
  2467. DWORD dwAspect, PCAXISMAPPINGS pamap, BOOL fReal )
  2468. {
  2469. int iaattr;
  2470. for (iaattr = 0; iaattr < cA(c_rgaattrJoy); iaattr++) {
  2471. PCAXISATTRIBUTES paattr = &c_rgaattrJoy[iaattr];
  2472. if (dwCaps & paattr->dwMask) {
  2473. CJoy_AddObject(this, pamap[iaattr].pguid, (cbX(LONG)*paattr->uidObj) + ib,
  2474. DIDFT_ABSAXIS, paattr->uidObj + uiObj, dwAspect, fReal);
  2475. }
  2476. }
  2477. }
  2478. /*****************************************************************************
  2479. *
  2480. * @doc INTERNAL
  2481. *
  2482. * @method void | CJoy | BuildDataFormat |
  2483. *
  2484. * Study the device capabilities and build the device
  2485. * data format.
  2486. *
  2487. *****************************************************************************/
  2488. void INTERNAL
  2489. CJoy_BuildDataFormat(PDJ this, PVXDAXISCAPS pvac, DWORD dwButtons, PCAXISMAPPINGS pamap, BOOL fReal)
  2490. {
  2491. DWORD dw;
  2492. this->dc.dwAxes = 0;
  2493. this->dc.dwButtons = 0;
  2494. this->dc.dwPOVs = 0;
  2495. this->df.dwSize = cbX(DIDATAFORMAT);
  2496. this->df.dwObjSize = cbX(DIOBJECTDATAFORMAT);
  2497. this->df.dwDataSize = sizeof(DIJOYSTATE2);
  2498. AssertF(this->df.dwFlags == 0);
  2499. this->df.dwNumObjs = 0;
  2500. /*
  2501. * Repeat for each set of axes.
  2502. */
  2503. #define CheckAxisOrder(fStart, p, f) \
  2504. CAssertF(FIELD_OFFSET(DIJOYSTATE2, p##f) == \
  2505. FIELD_OFFSET(DIJOYSTATE2, fStart) + ibJoyStateAxis##f) \
  2506. CheckAxisOrder(lX, l, X);
  2507. CheckAxisOrder(lX, l, Y);
  2508. CheckAxisOrder(lX, l, Z);
  2509. CheckAxisOrder(lX, l, Rx);
  2510. CheckAxisOrder(lX, l, Ry);
  2511. CheckAxisOrder(lX, l, Rz);
  2512. CheckAxisOrder(lX, rgl, Slider);
  2513. if (pvac->dwPos & JOYPF_POSITION) {
  2514. CJoy_BuildAxes(this, pvac->dwPos, FIELD_OFFSET(DIJOYSTATE2, lX),
  2515. iobjPositions, DIDOI_ASPECTPOSITION, pamap, fReal);
  2516. }
  2517. CheckAxisOrder(lVX, lV, X);
  2518. CheckAxisOrder(lVX, lV, Y);
  2519. CheckAxisOrder(lVX, lV, Z);
  2520. CheckAxisOrder(lVX, lV, Rx);
  2521. CheckAxisOrder(lVX, lV, Ry);
  2522. CheckAxisOrder(lVX, lV, Rz);
  2523. CheckAxisOrder(lVX, rglV, Slider);
  2524. if (pvac->dwPos & JOYPF_VELOCITY) {
  2525. CJoy_BuildAxes(this, pvac->dwVel, FIELD_OFFSET(DIJOYSTATE2, lVX),
  2526. iobjVelocities, DIDOI_ASPECTVELOCITY, pamap, fReal);
  2527. }
  2528. CheckAxisOrder(lAX, lA, X);
  2529. CheckAxisOrder(lAX, lA, Y);
  2530. CheckAxisOrder(lAX, lA, Z);
  2531. CheckAxisOrder(lAX, lA, Rx);
  2532. CheckAxisOrder(lAX, lA, Ry);
  2533. CheckAxisOrder(lAX, lA, Rz);
  2534. CheckAxisOrder(lAX, rglA, Slider);
  2535. if (pvac->dwPos & JOYPF_ACCELERATION) {
  2536. CJoy_BuildAxes(this, pvac->dwAccel, FIELD_OFFSET(DIJOYSTATE2, lAX),
  2537. iobjAccels, DIDOI_ASPECTACCEL, pamap, fReal);
  2538. }
  2539. CheckAxisOrder(lFX, lF, X);
  2540. CheckAxisOrder(lFX, lF, Y);
  2541. CheckAxisOrder(lFX, lF, Z);
  2542. CheckAxisOrder(lFX, lF, Rx);
  2543. CheckAxisOrder(lFX, lF, Ry);
  2544. CheckAxisOrder(lFX, lF, Rz);
  2545. CheckAxisOrder(lFX, rglF, Slider);
  2546. if (pvac->dwPos & JOYPF_FORCE) {
  2547. CJoy_BuildAxes(this, pvac->dwForce, FIELD_OFFSET(DIJOYSTATE2, lFX),
  2548. iobjForces, DIDOI_ASPECTFORCE, pamap, fReal);
  2549. }
  2550. #undef CheckAxisOrder
  2551. this->dc.dwAxes = this->df.dwNumObjs;
  2552. /*
  2553. * Doing the POVs is a bit tricky but not that bad.
  2554. */
  2555. for (dw = 0; dw < cJoyStatePOVTotal; dw++) {
  2556. if (pvac->dwPos & JOYPF_POV(dw)) {
  2557. CJoy_AddObject(this, &GUID_POV,
  2558. FIELD_OFFSET(DIJOYSTATE2, rgdwPOV[dw]),
  2559. DIDFT_POV, dw, DIDOI_ASPECTUNKNOWN, fReal);
  2560. this->dc.dwPOVs++;
  2561. }
  2562. }
  2563. /*
  2564. * Doing the buttons is easy since they don't have
  2565. * any interesting attributes.
  2566. */
  2567. this->dc.dwButtons = min(dwButtons, cJoyStateButtonTotal);
  2568. for (dw = 0; dw < this->dc.dwButtons; dw++) {
  2569. CJoy_AddObject(this, &GUID_Button,
  2570. FIELD_OFFSET(DIJOYSTATE2, rgbButtons[dw]),
  2571. DIDFT_PSHBUTTON, dw, DIDOI_ASPECTUNKNOWN, fReal);
  2572. }
  2573. AssertF(this->df.dwNumObjs <= cJoyStateObjTotal);
  2574. }
  2575. /*****************************************************************************
  2576. *
  2577. * @doc INTERNAL
  2578. *
  2579. * @method HRESULT | CJoy | PreInit |
  2580. *
  2581. * Preallocate all the memory we will need up front, so we
  2582. * don't waste time reallocating later.
  2583. *
  2584. *****************************************************************************/
  2585. HRESULT INLINE
  2586. CJoy_PreInit(PDJ this)
  2587. {
  2588. HRESULT hres;
  2589. hres = ReallocCbPpv(cbCxX(cJoyStateObjTotal, DIOBJECTDATAFORMAT),
  2590. &this->df.rgodf);
  2591. return hres;
  2592. }
  2593. /*****************************************************************************
  2594. *
  2595. * @doc INTERNAL
  2596. *
  2597. * @method HRESULT | CJoy | InitRing0 |
  2598. *
  2599. * Initialize the ring 0 information maintained about the object.
  2600. *
  2601. * Broken out from CJoy_Init to make things less monolithic.
  2602. *
  2603. *****************************************************************************/
  2604. HRESULT INTERNAL
  2605. CJoy_InitRing0(PDJ this)
  2606. {
  2607. HRESULT hres;
  2608. VXDDEVICEFORMAT devf;
  2609. /*
  2610. * Note that we now allow the device to be created even if
  2611. * the joystick doesn't physically exist. This is necessary
  2612. * so that IDirectInputJoyConfig8 can calibrate the joystick
  2613. * that doesn't exist yet.
  2614. *
  2615. * This won't confuse applications, however, because
  2616. * IDirectInput::EnumDevices will not return phantom devices
  2617. * unless the application explicitly asks for phantom devices
  2618. * to be included.
  2619. */
  2620. /*
  2621. * See if this joystick supports fancy notifications.
  2622. * The default is "no".
  2623. *
  2624. * Also see if this is really a HID device (and hence our
  2625. * interface is an alias).
  2626. *
  2627. * These things are all 9x-specific.
  2628. */
  2629. #ifdef WINNT
  2630. this->dc.dwFlags |= DIDC_POLLEDDEVICE;
  2631. #else
  2632. VXDINITPARMS vip;
  2633. this->dc.dwFlags |= DIDC_POLLEDDEVICE;
  2634. hres = Hel_Joy_GetInitParms(this->idJoy, &vip);
  2635. if (SUCCEEDED(hres))
  2636. {
  2637. if (vip.dwFlags & VIP_SENDSNOTIFY)
  2638. {
  2639. this->dc.dwFlags &= ~DIDC_POLLEDDEVICE;
  2640. }
  2641. if (vip.dwFlags & VIP_ISHID)
  2642. {
  2643. /*
  2644. * Use VJOYD as Alias if the device is HID
  2645. * (the may be revised in CJoy_InitRing3).
  2646. */
  2647. this->dc.dwFlags |= DIDC_ALIAS;
  2648. }
  2649. }
  2650. #endif /* WINNT */
  2651. this->dc.dwSize = cbX(DIDEVCAPS);
  2652. /*
  2653. * Build the worst-case data format for the VxD.
  2654. *
  2655. * We must always build worst-case because sometime
  2656. * later, a newer more capable joystick might show up,
  2657. * with more objects than the one we imprinted on.
  2658. *
  2659. * Use the GUIDs for a joystick for now, and pass the flag
  2660. * indicating that there is no need to check registry settings.
  2661. */
  2662. CJoy_BuildDataFormat(this, &c_vacMax, cJoyStateButtonTotal, c_rgamapJoy, FALSE);
  2663. /*
  2664. * It won't actually get that high because of the
  2665. * nonexistent Rx and Ry axes.
  2666. */
  2667. AssertF(this->df.dwNumObjs <= cJoyStateObjTotal);
  2668. devf.cbData = cbX(DIJOYSTATE2);
  2669. devf.dwExtra = this->idJoy;
  2670. devf.cObj = this->df.dwNumObjs;
  2671. devf.rgodf = this->df.rgodf;
  2672. devf.dwEmulation = 0;
  2673. hres = Hel_Joy_CreateInstance(&devf, &this->pvi);
  2674. if (SUCCEEDED(hres)) {
  2675. AssertF(this->pvi);
  2676. this->pjsPhys = this->pvi->pState;
  2677. } else { /* IOCTL failed; hres already set */
  2678. }
  2679. return hres;
  2680. }
  2681. /*****************************************************************************
  2682. *
  2683. * @doc INTERNAL
  2684. *
  2685. * @method HRESULT | CJoy | InitSemanticMap |
  2686. *
  2687. * Initialize the semantic mapping information.
  2688. *
  2689. *****************************************************************************/
  2690. void INLINE
  2691. CJoy_GetAxisMap( PDJ this, PCAXISMAPPINGS* ppamap )
  2692. {
  2693. if( GET_DIDEVICE_TYPEANDSUBTYPE( this->dc.dwDevType )
  2694. == MAKE_DIDEVICE_TYPE( DI8DEVTYPE_1STPERSON, DI8DEVTYPE1STPERSON_SIXDOF ) )
  2695. {
  2696. *ppamap = &c_rgamap6DOF[0];
  2697. }
  2698. else if( ( GET_DIDEVICE_TYPE( this->dc.dwDevType ) == DI8DEVTYPE_DRIVING )
  2699. && ( this->dc.dwAxes > 2 ) )
  2700. {
  2701. /*
  2702. * There are three common forms of pedals
  2703. * a. Split Y axis, below center accel, above brake
  2704. * b. Y break, Z accel
  2705. * c. Y accel, R brake
  2706. * a. is just like a joystick but b and c need their own look ups
  2707. *
  2708. * Use a registry flag if one is set, otherwise, select using HASR
  2709. * as there is at least one case of an X,Y,R device that reports
  2710. * the presence of a bogus Z axis.
  2711. */
  2712. switch( this->typi.dwFlags2 & JOYTYPE_INFOMASK )
  2713. {
  2714. case JOYTYPE_INFOYYPEDALS:
  2715. *ppamap = &c_rgamapJoy[0];
  2716. break;
  2717. case JOYTYPE_INFOZYPEDALS:
  2718. *ppamap = &c_rgamapCarZY[0];
  2719. break;
  2720. case JOYTYPE_INFOYRPEDALS:
  2721. *ppamap = &c_rgamapCarYR[0];
  2722. break;
  2723. case JOYTYPE_INFOZRPEDALS:
  2724. *ppamap = &c_rgamapCarZR[0];
  2725. break;
  2726. default:
  2727. if( ( this->cfg.hwc.hws.dwFlags & JOY_HWS_HASR )
  2728. && ( this->cfg.hwc.hws.dwFlags & JOY_HWS_HASZ ) )
  2729. {
  2730. *ppamap = &c_rgamapCarZR[0];
  2731. }
  2732. else if( this->cfg.hwc.hws.dwFlags & JOY_HWS_HASR )
  2733. {
  2734. *ppamap = &c_rgamapCarYR[0];
  2735. }
  2736. else if( this->cfg.hwc.hws.dwFlags & JOY_HWS_HASZ )
  2737. {
  2738. *ppamap = &c_rgamapCarZY[0];
  2739. }
  2740. else
  2741. {
  2742. *ppamap = &c_rgamapJoy[0];
  2743. }
  2744. }
  2745. }
  2746. else
  2747. {
  2748. /*
  2749. * The default map is joystick
  2750. *
  2751. * Check for Z axis behavior override
  2752. * Since the default behavior is to use Z as a slider,
  2753. * only the override to a Z axis is needed here.
  2754. */
  2755. if( this->typi.dwFlags2 & JOYTYPE_INFOZISZ )
  2756. {
  2757. *ppamap = &c_rgamapZJoy[0];
  2758. }
  2759. else
  2760. {
  2761. *ppamap = &c_rgamapJoy[0];
  2762. }
  2763. }
  2764. }
  2765. /*****************************************************************************
  2766. *
  2767. * @doc INTERNAL
  2768. *
  2769. * @method HRESULT | CJoy | InitSemanticMap |
  2770. *
  2771. * Initialize the semantic mapping information.
  2772. *
  2773. *****************************************************************************/
  2774. HRESULT INLINE
  2775. CJoy_InitSemanticMap( PDJ this, DWORD dwAxisMask, PCAXISMAPPINGS pamap )
  2776. {
  2777. HRESULT hres;
  2778. /*
  2779. * Prefix warns (mb:34681) that the pointer would be null if the
  2780. * number of objects on the device is zero.
  2781. * This cannot be, so assert it but don't check in retail.
  2782. */
  2783. AssertF( this->dc.dwAxes + this->dc.dwPOVs + this->dc.dwButtons != 0 );
  2784. if( SUCCEEDED( hres = AllocCbPpv(cbCxX(
  2785. (this->dc.dwAxes + this->dc.dwPOVs + this->dc.dwButtons ), DIDOBJDEFSEM),
  2786. &this->rgObjSem) ) )
  2787. {
  2788. UINT Idx;
  2789. PDIDOBJDEFSEM pObjSem = this->rgObjSem;
  2790. LPDIOBJECTDATAFORMAT podf;
  2791. /*
  2792. * The axis mapping table does most of the work
  2793. */
  2794. for( Idx = 0; Idx < cA(c_rgaattrJoy); Idx++ )
  2795. {
  2796. PCAXISATTRIBUTES paattr = &c_rgaattrJoy[Idx];
  2797. if( dwAxisMask & c_rgaattrJoy[Idx].dwMask)
  2798. {
  2799. pObjSem->dwID = DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE(c_rgaattrJoy[Idx].uidObj);
  2800. pObjSem->dwSemantic = pamap[Idx].dwSemantic;
  2801. pObjSem++;
  2802. }
  2803. }
  2804. AssertF( pObjSem == &this->rgObjSem[this->dc.dwAxes] );
  2805. /*
  2806. * POVs and buttons require no look ups.
  2807. */
  2808. for( Idx = 0; Idx < this->dc.dwPOVs; Idx++ )
  2809. {
  2810. pObjSem->dwID = DIDFT_POV | DIDFT_MAKEINSTANCE(Idx);
  2811. pObjSem->dwSemantic = DISEM_TYPE_POV | DISEM_INDEX_SET(Idx+1);
  2812. pObjSem++;
  2813. }
  2814. AssertF( pObjSem == &this->rgObjSem[this->dc.dwAxes + this->dc.dwPOVs] );
  2815. for( Idx = 0; Idx < this->dc.dwButtons; Idx++ )
  2816. {
  2817. pObjSem->dwID = DIDFT_PSHBUTTON | DIDFT_MAKEINSTANCE(Idx);
  2818. pObjSem->dwSemantic = DISEM_TYPE_BUTTON | DISEM_INDEX_SET(Idx+1);
  2819. pObjSem++;
  2820. }
  2821. AssertF( pObjSem == &this->rgObjSem[this->dc.dwAxes + this->dc.dwPOVs + this->dc.dwButtons] );
  2822. /*
  2823. * Now go back to pick up any extra type bits, such as FF.
  2824. * Because we use the same order in creating the semantic table as
  2825. * is used to create the data format, this is optimized to only
  2826. * search from where the previous match was found. We cannot rely
  2827. * on a one-to-one mapping because of the non-positional axes.
  2828. */
  2829. podf = &this->df.rgodf[this->df.dwNumObjs];
  2830. for( pObjSem--; pObjSem >= this->rgObjSem; pObjSem-- )
  2831. {
  2832. do
  2833. {
  2834. podf--;
  2835. if( ( podf->dwType & (DIDFT_INSTANCEMASK | DIDFT_TYPEMASK) )
  2836. == pObjSem->dwID )
  2837. {
  2838. pObjSem->dwID = podf->dwType;
  2839. break;
  2840. }
  2841. } while( podf >= this->df.rgodf );
  2842. AssertF( podf >= this->df.rgodf );
  2843. }
  2844. }
  2845. return hres;
  2846. }
  2847. /*****************************************************************************
  2848. *
  2849. * @doc INTERNAL
  2850. *
  2851. * @method HRESULT | CJoy | InitRing3 |
  2852. *
  2853. * Initialize the ring 3 information maintained about the object.
  2854. *
  2855. * Broken out from CJoy_Init to make things less monolithic.
  2856. *
  2857. *****************************************************************************/
  2858. HRESULT INTERNAL
  2859. CJoy_InitRing3(PDJ this )
  2860. {
  2861. HRESULT hres;
  2862. VXDAXISCAPS vac;
  2863. PCAXISMAPPINGS pamap;
  2864. /*
  2865. * We must ask for DIJC_CALLOUT even though we don't care,
  2866. * because that will trigger the Microsoft Gamepad hack-o-rama.
  2867. */
  2868. hres = JoyReg_GetConfig(this->idJoy, &this->cfg,
  2869. DIJC_REGHWCONFIGTYPE | DIJC_CALLOUT );
  2870. if (SUCCEEDED(hres)) {
  2871. /*
  2872. * Fix phantom devices bug. See manbug: 23186
  2873. */
  2874. if( this->cfg.hwc.dwType == JOY_HW_NONE ) {
  2875. hres = E_FAIL;
  2876. goto done;
  2877. }
  2878. /*
  2879. * Open the type key so we can grovel into the type info.
  2880. * If the RegOpenKeyEx fails, the value of this->hkType
  2881. * will stay zero so we won't run with garbage.
  2882. *
  2883. * Note that failure to open the type key is not an error.
  2884. *
  2885. * We need to do this before building the data format, because
  2886. * BuildDataFormat needs the hkType to get the attributes.
  2887. */
  2888. AssertF(this->hkType == 0);
  2889. /*
  2890. * Only open the key if it is intended to exist
  2891. */
  2892. if( this->cfg.hwc.dwUsageSettings & JOY_US_ISOEM )
  2893. {
  2894. JoyReg_OpenTypeKey(this->cfg.wszType, MAXIMUM_ALLOWED,
  2895. REG_OPTION_NON_VOLATILE, &this->hkType);
  2896. }
  2897. if FAILED (JoyReg_OpenPropKey(this->cfg.wszType, MAXIMUM_ALLOWED, REG_OPTION_NON_VOLATILE, &this->hkProp))
  2898. {
  2899. /*
  2900. * If we fail to open the prop key - we will continue to function with loss in functionality
  2901. * Specifically no device images, etc
  2902. */
  2903. }
  2904. hres = Hel_Joy_GetAxisCaps(this->idJoy, &vac, &this->cfg.hwc );
  2905. /*
  2906. * HACKHACK
  2907. * In the case of a DX5 VJoyD, the POV0 flag can be stripped out of
  2908. * the vac if the poll returns a POV0 value other than (DWORD)-1.
  2909. * So add it back if the registry says we have it.
  2910. */
  2911. if( this->cfg.hwc.hws.dwFlags & JOY_HWS_HASPOV )
  2912. {
  2913. DWORD dwVersion = GetVersion();
  2914. /*
  2915. * Check for any Win95 version
  2916. */
  2917. if( ( LOBYTE( dwVersion ) == 4 )
  2918. && ( HIBYTE( LOWORD( dwVersion ) ) < 10 ) )
  2919. {
  2920. vac.dwPos |= JOYPF_POV0;
  2921. }
  2922. }
  2923. AssertF(SUCCEEDED(hres));
  2924. /*
  2925. * Previous versions of DInput allow a POV granularity of 1 if
  2926. * joyGetCaps returned a wCaps with JOYCAPS_POV4DIR set.
  2927. * This does no good as neither drivers nor WinMM really
  2928. * support this.
  2929. */
  2930. this->dwPOVGranularity = 9000;
  2931. /*
  2932. * Logical ranges must be done before physical ranges,
  2933. * because initializing the physical ranges will also
  2934. * recompute the ramp conversion parameters.
  2935. */
  2936. CJoy_InitLogRanges(this);
  2937. CJoy_InitPhysRanges(this, &this->cfg.hwc);
  2938. /*
  2939. * Need to init from HWC before building real data format so type
  2940. * overrides can be taken into account. Unfortunately, until the
  2941. * data format is built, we don't know what axes are available.
  2942. * Since the code is already here, build the data format again.
  2943. * Use the joystick look-ups and don't bother with registry flags.
  2944. */
  2945. CJoy_BuildDataFormat(this, &vac, this->cfg.hwc.hws.dwNumButtons, c_rgamapJoy, FALSE );
  2946. hres = CJoy_InitFromHwc( this );
  2947. if( SUCCEEDED( hres ) )
  2948. {
  2949. CJoy_GetAxisMap( this, &pamap );
  2950. /*
  2951. * At last, time to build the data format for real
  2952. */
  2953. CJoy_BuildDataFormat(this, &vac, this->cfg.hwc.hws.dwNumButtons, pamap, TRUE );
  2954. hres = CJoy_InitSemanticMap( this, vac.dwPos, pamap );
  2955. }
  2956. #ifndef WINNT
  2957. if( this->hkType )
  2958. {
  2959. DWORD dwFlags1;
  2960. if( SUCCEEDED( JoyReg_GetValue( this->hkType,
  2961. REGSTR_VAL_FLAGS1, REG_BINARY,
  2962. &dwFlags1,
  2963. cbX(dwFlags1) ) ) )
  2964. {
  2965. if( dwFlags1 & JOYTYPE_NOHIDDIRECT )
  2966. {
  2967. this->dc.dwFlags &= ~DIDC_ALIAS;
  2968. }
  2969. }
  2970. }
  2971. #endif
  2972. this->diHacks.nMaxDeviceNameLength = MAX_PATH;
  2973. } else {
  2974. RPF("Unexpected error 0x%08x obtaining joystick capabilities",hres);
  2975. hres = E_FAIL;
  2976. }
  2977. done:
  2978. return hres;
  2979. }
  2980. /*****************************************************************************
  2981. *
  2982. * @doc INTERNAL
  2983. *
  2984. * @method HRESULT | CJoy | Init |
  2985. *
  2986. * Initialize the object by establishing the data format
  2987. * based on the joystick capabilities.
  2988. *
  2989. *****************************************************************************/
  2990. HRESULT INTERNAL
  2991. CJoy_Init(PDJ this, REFGUID rguid)
  2992. {
  2993. HRESULT hres;
  2994. EnterProc(CJoy_Init, (_ "pG", this, rguid));
  2995. this->idJoy = rguid->Data1 & 0xF;
  2996. /* If joystick number is vaguely valid */
  2997. if (this->idJoy < cJoyMax) {
  2998. if (SUCCEEDED(hres = CJoy_PreInit(this)) &&
  2999. SUCCEEDED(hres = CJoy_InitRing0(this)) &&
  3000. SUCCEEDED(hres = CJoy_InitRing3(this))) {
  3001. }
  3002. } else {
  3003. hres = DIERR_DEVICENOTREG;
  3004. }
  3005. ExitOleProc();
  3006. return hres;
  3007. }
  3008. /*****************************************************************************
  3009. *
  3010. * CJoy_New (constructor)
  3011. *
  3012. *****************************************************************************/
  3013. STDMETHODIMP
  3014. CJoy_New(PUNK punkOuter, REFGUID rguid, RIID riid, PPV ppvObj)
  3015. {
  3016. HRESULT hres;
  3017. EnterProcI(IDirectInputDeviceCallback::Joy::<constructor>,
  3018. (_ "Gp", riid, ppvObj));
  3019. hres = Common_NewRiid(CJoy, punkOuter, riid, ppvObj);
  3020. if (SUCCEEDED(hres)) {
  3021. /* Must use _thisPv in case of aggregation */
  3022. PDJ this = _thisPv(*ppvObj);
  3023. if (SUCCEEDED(hres = CJoy_Init(this, rguid))) {
  3024. } else {
  3025. Invoke_Release(ppvObj);
  3026. }
  3027. }
  3028. ExitOleProcPpvR(ppvObj);
  3029. return hres;
  3030. }
  3031. /*****************************************************************************
  3032. *
  3033. * @doc INTERNAL
  3034. *
  3035. * @method HRESULT | CJoy | SetDIData |
  3036. *
  3037. * Set DirectInput version and apphack data from CDIDev *.
  3038. *
  3039. * @parm DWORD | dwVer |
  3040. *
  3041. * DirectInput version
  3042. *
  3043. * @parm LPVOID | lpdihacks |
  3044. *
  3045. * AppHack data
  3046. *
  3047. * @returns
  3048. *
  3049. * <c S_OK> because we cannot fail.
  3050. *
  3051. *****************************************************************************/
  3052. STDMETHODIMP
  3053. CJoy_SetDIData(PDICB pdcb, DWORD dwVer, LPVOID lpdihacks)
  3054. {
  3055. PDJ this;
  3056. EnterProcI(IDirectInputDeviceCallback::Joy::SetDIData,
  3057. (_ "pup", pdcb, dwVer, lpdihacks));
  3058. /*
  3059. * This is an internal interface, so we can skimp on validation.
  3060. */
  3061. this = _thisPvNm(pdcb, dcb);
  3062. this->dwVersion = dwVer;
  3063. CopyMemory(&this->diHacks, (LPDIAPPHACKS)lpdihacks, sizeof(this->diHacks));
  3064. ExitProcR();
  3065. return S_OK;
  3066. }
  3067. /*****************************************************************************
  3068. *
  3069. * @doc INTERNAL
  3070. *
  3071. * @method HRESULT | CJoy | BuildDefaultActionMap |
  3072. *
  3073. * Generate default mappings for the objects on this device.
  3074. *
  3075. * @parm LPDIACTIONFORMATW | pActionFormat |
  3076. *
  3077. * Actions to map.
  3078. *
  3079. * @parm DWORD | dwFlags |
  3080. *
  3081. * Flags used to indicate mapping preferences.
  3082. *
  3083. * @parm REFGUID | guidInst |
  3084. *
  3085. * Device instance GUID.
  3086. *
  3087. * @returns
  3088. *
  3089. * <c E_NOTIMPL>
  3090. *
  3091. *****************************************************************************/
  3092. STDMETHODIMP
  3093. CJoy_BuildDefaultActionMap
  3094. (
  3095. PDICB pdcb,
  3096. LPDIACTIONFORMATW paf,
  3097. DWORD dwFlags,
  3098. REFGUID guidInst
  3099. )
  3100. {
  3101. HRESULT hres;
  3102. PDJ this;
  3103. PDIDOBJDEFSEM pObjDefSemTemp;
  3104. /*
  3105. * This is an internal interface, so we can skimp on validation.
  3106. */
  3107. EnterProcI(IDirectInputDeviceCallback::Joy::BuildDefaultActionMap,
  3108. (_ "ppxG", pdcb, paf, dwFlags, guidInst));
  3109. this = _thisPvNm(pdcb, dcb);
  3110. /*
  3111. * Prefix warns (win:199090) that the pointer would be null if the
  3112. * size of the semantic object list is zero.
  3113. * This cannot be, so assert it but don't check in retail.
  3114. */
  3115. AssertF( cbCxX( this->dc.dwAxes + this->dc.dwPOVs + this->dc.dwButtons, DIDOBJDEFSEM ) );
  3116. hres = AllocCbPpv( cbCxX(
  3117. ( this->dc.dwAxes + this->dc.dwPOVs + this->dc.dwButtons ), DIDOBJDEFSEM ),
  3118. &pObjDefSemTemp );
  3119. if( SUCCEEDED( hres ) )
  3120. {
  3121. memcpy( pObjDefSemTemp, this->rgObjSem, cbCxX(
  3122. ( this->dc.dwAxes + this->dc.dwPOVs + this->dc.dwButtons ), DIDOBJDEFSEM ) );
  3123. hres = CMap_BuildDefaultDevActionMap( paf, dwFlags, guidInst,
  3124. pObjDefSemTemp, this->dc.dwAxes, this->dc.dwPOVs, this->dc.dwButtons );
  3125. FreePv( pObjDefSemTemp );
  3126. }
  3127. ExitOleProcR();
  3128. return hres;
  3129. }
  3130. /*****************************************************************************
  3131. *
  3132. * The long-awaited vtbls and templates
  3133. *
  3134. *****************************************************************************/
  3135. #define CJoy_Signature 0x2044424B /* "Joy " */
  3136. Interface_Template_Begin(CJoy)
  3137. Primary_Interface_Template(CJoy, IDirectInputDeviceCallback)
  3138. Interface_Template_End(CJoy)
  3139. Primary_Interface_Begin(CJoy, IDirectInputDeviceCallback)
  3140. CJoy_GetInstance,
  3141. CJoy_GetVersions,
  3142. CJoy_GetDataFormat,
  3143. CJoy_GetObjectInfo,
  3144. CJoy_GetCapabilities,
  3145. CDefDcb_Acquire,
  3146. CDefDcb_Unacquire,
  3147. CJoy_GetDeviceState,
  3148. CJoy_GetDeviceInfo,
  3149. CJoy_GetProperty,
  3150. CJoy_SetProperty,
  3151. CDefDcb_SetEventNotification,
  3152. CJoy_SetCooperativeLevel,
  3153. CJoy_RunControlPanel,
  3154. CJoy_CookDeviceData,
  3155. CJoy_CreateEffect,
  3156. CJoy_GetFFConfigKey,
  3157. CDefDcb_SendDeviceData,
  3158. CJoy_Poll,
  3159. CDefDcb_GetUsage,
  3160. CDefDcb_MapUsage,
  3161. CJoy_SetDIData,
  3162. CJoy_BuildDefaultActionMap,
  3163. Primary_Interface_End(CJoy, IDirectInputDeviceCallback)
  3164. #endif