Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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