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.

3146 lines
89 KiB

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