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.

1341 lines
36 KiB

  1. /*****************************************************************************
  2. *
  3. * DIEffJ.c
  4. *
  5. * Copyright (c) 1996 Microsoft Corporation. All Rights Reserved.
  6. *
  7. * Abstract:
  8. *
  9. * Dummy effect driver for joystick.
  10. *
  11. * Contents:
  12. *
  13. * CJoyEff_CreateInstance
  14. *
  15. *****************************************************************************/
  16. #include "dinputpr.h"
  17. #if defined(IDirectInputDevice2Vtbl) && defined(DEMONSTRATION_FFDRIVER)
  18. /*****************************************************************************
  19. *
  20. * The sqiffle for this file.
  21. *
  22. *****************************************************************************/
  23. #define sqfl sqflJoyEff
  24. /****************************************************************************
  25. *
  26. * @doc DDK
  27. *
  28. * @topic DirectInput force feedback effect drivers |
  29. *
  30. * DirectInput instantiates the force feedback effect driver
  31. * by creating the object named by the CLSID stored in the
  32. * OEMForceFeedback registry subkey of the joystick type
  33. * key.
  34. *
  35. * Note, however, that since applications using DirectInput
  36. * need not load OLE, the effect driver should be careful
  37. * not to rely on OLE-specific behavior.
  38. * For example, applications using DirectInput cannot be
  39. * relied upon to call <f CoFreeUnusedLibraries>.
  40. * DirectInput will perform the standard COM operations to
  41. * instantiate the effect driver object. The only visible
  42. * effect this should have on the implementation of the
  43. * effect driver is as follows:
  44. *
  45. * When DirectInput has released the last effect driver
  46. * object, it will manually perform a <f FreeLibrary> of
  47. * the effect driver DLL. Consequently, if the effect
  48. * driver DLL creates additional resources that are not
  49. * associated with the effect driver object, it should
  50. * manually <f LoadLibrary> itself to artificially
  51. * increase its DLL reference count, thereby preventing
  52. * the <f FreeLibrary> from DirectInput from unloading
  53. * the DLL prematurely.
  54. *
  55. * In particular, if the effect driver DLL creates a worker
  56. * thread, the effect driver must perform this artificial
  57. * <f LoadLibrary> for as long as the worker thread exists.
  58. * When the worker thread is no longer needed (for example, upon
  59. * notification from the last effect driver object as it
  60. * is being destroyed), the worker thread should call
  61. * <f FreeLibraryAndExitThread> to decrement the DLL reference
  62. * count and terminate the thread.
  63. *
  64. * All magnitude and gain values used by DirectInput
  65. * are uniform and linear across the range. Any
  66. * nonlinearity in the physical device must be
  67. * handled by the device driver so that the application
  68. * sees a linear device.
  69. *
  70. *****************************************************************************/
  71. /*****************************************************************************
  72. *
  73. * Declare the interfaces we will be providing.
  74. *
  75. * WARNING! If you add a secondary interface, you must also change
  76. * CJoyEff_New!
  77. *
  78. *****************************************************************************/
  79. Primary_Interface(CJoyEff, IDirectInputEffectDriver);
  80. /*****************************************************************************
  81. *
  82. * @doc INTERNAL
  83. *
  84. * @struct JEFFECT |
  85. *
  86. * Dummy structure that records information about an effect.
  87. *
  88. * @field DWORD | tmDuration |
  89. *
  90. * Putative duration for effect.
  91. *
  92. * @field DWORD | tmStart |
  93. *
  94. * Time the effect started, or zero if not playing.
  95. *
  96. * @field BOOL | fInUse |
  97. *
  98. * Nonzero if this effect is allocated.
  99. *
  100. *****************************************************************************/
  101. typedef struct JEFFECT {
  102. DWORD tmDuration;
  103. DWORD tmStart;
  104. BOOL fInUse;
  105. } JEFFECT, *PJEFFECT;
  106. /*****************************************************************************
  107. *
  108. * @doc INTERNAL
  109. *
  110. * @struct CJoyEff |
  111. *
  112. * A dummy <i IDirectInputEffectDriver> object for the
  113. * generic joystick.
  114. *
  115. * @field IDirectInputEffectDriver | didc |
  116. *
  117. * The object (containing vtbl).
  118. *
  119. * @field BOOL | fCritInited:1 |
  120. *
  121. * Set if the critical section has been initialized.
  122. *
  123. * @field DWORD | state |
  124. *
  125. * The current device state.
  126. *
  127. * @field LONG | cCrit |
  128. *
  129. * Number of times the critical section has been taken.
  130. * Used only in XDEBUG to check whether the caller is
  131. * releasing the object while another method is using it.
  132. *
  133. * @field DWORD | thidCrit |
  134. *
  135. * The thread that is currently in the critical section.
  136. * Used only in DEBUG for internal consistency checking.
  137. *
  138. * @field CRITICAL_SECTION | crst |
  139. *
  140. * Object critical section. Must be taken when accessing
  141. * volatile member variables.
  142. *
  143. * @field JEFFECT | rgjeff[cjeffMax] |
  144. *
  145. * Information for each effect.
  146. *
  147. *****************************************************************************/
  148. #define cjeffMax 8 /* Up to 8 simultaneous effects */
  149. typedef struct CJoyEff {
  150. /* Supported interfaces */
  151. IDirectInputEffectDriver ded;
  152. BOOL fCritInited;
  153. DWORD state;
  154. DWORD dwGain;
  155. RD(LONG cCrit;)
  156. D(DWORD thidCrit;)
  157. CRITICAL_SECTION crst;
  158. JEFFECT rgjeff[cjeffMax];
  159. } CJoyEff, DJE, *PDJE;
  160. typedef IDirectInputEffectDriver DED, *PDED;
  161. #define ThisClass CJoyEff
  162. #define ThisInterface IDirectInputEffectDriver
  163. #define riidExpected &IID_IDirectInputEffectDriver
  164. /*****************************************************************************
  165. *
  166. * CJoyEff::QueryInterface (from IUnknown)
  167. * CJoyEff::AddRef (from IUnknown)
  168. * CJoyEff::Release (from IUnknown)
  169. *
  170. *****************************************************************************/
  171. /*****************************************************************************
  172. *
  173. * @doc DDK
  174. *
  175. * @method HRESULT | IDirectInputEffectDriver | QueryInterface |
  176. *
  177. * Gives a client access to other interfaces on an object.
  178. *
  179. * @cwrap LPDIRECTINPUTEFFECTDRIVER | lpEffectDriver
  180. *
  181. * @parm IN REFIID | riid |
  182. *
  183. * The requested interface's IID.
  184. *
  185. * @parm OUT LPVOID * | ppvObj |
  186. *
  187. * Receives a pointer to the obtained interface.
  188. *
  189. * @returns
  190. *
  191. * Returns a COM error code.
  192. *
  193. * @xref OLE documentation for <mf IUnknown::QueryInterface>.
  194. *
  195. *****************************************************************************
  196. *
  197. * @doc DDK
  198. *
  199. * @method HRESULT | IDirectInputEffectDriver | AddRef |
  200. *
  201. * Increments the reference count for the interface.
  202. *
  203. * @cwrap LPDIRECTINPUTEFFECTDRIVER | lpEffectDriver
  204. *
  205. * @returns
  206. *
  207. * Returns the object reference count.
  208. *
  209. * @xref OLE documentation for <mf IUnknown::AddRef>.
  210. *
  211. *****************************************************************************
  212. *
  213. * @doc DDK
  214. *
  215. * @method HRESULT | IDirectInputEffectDriver | Release |
  216. *
  217. * Decrements the reference count for the interface.
  218. * If the reference count on the object falls to zero,
  219. * the object is freed from memory.
  220. *
  221. * @cwrap LPDIRECTINPUTEFFECTDRIVER | lpEffectDriver
  222. *
  223. * @returns
  224. *
  225. * Returns the object reference count.
  226. *
  227. * @xref OLE documentation for <mf IUnknown::Release>.
  228. *
  229. *****************************************************************************
  230. *
  231. * @doc INTERNAL
  232. *
  233. * @method HRESULT | CJoyEff | QIHelper |
  234. *
  235. * We don't have any dynamic interfaces and simply forward
  236. * to <f Common_QIHelper>.
  237. *
  238. * @parm IN REFIID | riid |
  239. *
  240. * The requested interface's IID.
  241. *
  242. * @parm OUT LPVOID * | ppvObj |
  243. *
  244. * Receives a pointer to the obtained interface.
  245. *
  246. *****************************************************************************
  247. *
  248. * @doc INTERNAL
  249. *
  250. * @method HRESULT | CJoyEff | AppFinalize |
  251. *
  252. * We don't have any weak pointers, so we can just
  253. * forward to <f Common_Finalize>.
  254. *
  255. * @parm PV | pvObj |
  256. *
  257. * Object being released from the application's perspective.
  258. *
  259. *****************************************************************************/
  260. #ifdef DEBUG
  261. Default_QueryInterface(CJoyEff)
  262. Default_AddRef(CJoyEff)
  263. Default_Release(CJoyEff)
  264. #else
  265. #define CJoyEff_QueryInterface Common_QueryInterface
  266. #define CJoyEff_AddRef Common_AddRef
  267. #define CJoyEff_Release Common_Release
  268. #endif
  269. #define CJoyEff_QIHelper Common_QIHelper
  270. #define CJoyEff_AppFinalize Common_AppFinalize
  271. /*****************************************************************************
  272. *
  273. * @doc INTERNAL
  274. *
  275. * @func void | CJoyEff_Finalize |
  276. *
  277. * Releases the resources of the device.
  278. *
  279. * @parm PV | pvObj |
  280. *
  281. * Object being released. Note that it may not have been
  282. * completely initialized, so everything should be done
  283. * carefully.
  284. *
  285. *****************************************************************************/
  286. void INTERNAL
  287. CJoyEff_Finalize(PV pvObj)
  288. {
  289. PDJE this = pvObj;
  290. if (this->fCritInited) {
  291. DeleteCriticalSection(&this->crst);
  292. }
  293. }
  294. /*****************************************************************************
  295. *
  296. * @doc INTERNAL
  297. *
  298. * @method void | CJoyEff | EnterCrit |
  299. *
  300. * Enter the object critical section.
  301. *
  302. * @cwrap PDJE | this
  303. *
  304. *****************************************************************************/
  305. void EXTERNAL
  306. CJoyEff_EnterCrit(PDJE this)
  307. {
  308. EnterCriticalSection(&this->crst);
  309. D(this->thidCrit = GetCurrentThreadId());
  310. RD(InterlockedIncrement(&this->cCrit));
  311. }
  312. /*****************************************************************************
  313. *
  314. * @doc INTERNAL
  315. *
  316. * @method void | CJoyEff | LeaveCrit |
  317. *
  318. * Leave the object critical section.
  319. *
  320. * @cwrap PDJE | this
  321. *
  322. *****************************************************************************/
  323. void EXTERNAL
  324. CJoyEff_LeaveCrit(PDJE this)
  325. {
  326. #ifdef XDEBUG
  327. AssertF(this->cCrit);
  328. AssertF(this->thidCrit == GetCurrentThreadId());
  329. if (InterlockedDecrement(&this->cCrit) == 0) {
  330. D(this->thidCrit = 0);
  331. }
  332. #endif
  333. LeaveCriticalSection(&this->crst);
  334. }
  335. /*****************************************************************************
  336. *
  337. * @doc INTERNAL
  338. *
  339. * @method BOOL | CJoyEff | InCrit |
  340. *
  341. * Nonzero if we are in the critical section.
  342. *
  343. *****************************************************************************/
  344. #ifdef DEBUG
  345. BOOL INTERNAL
  346. CJoyEff_InCrit(PDJE this)
  347. {
  348. return this->cCrit && this->thidCrit == GetCurrentThreadId();
  349. }
  350. #endif
  351. /*****************************************************************************
  352. *
  353. * @doc INTERNAL
  354. *
  355. * @method HRESULT | CJoyEff | IsValidId |
  356. *
  357. * Determine whether the effect pseudo-handle is valid.
  358. * If so, returns a pointer to the <t JEFFECT>.
  359. *
  360. * @cwrap PDJE | this
  361. *
  362. * @parm DWORD | dwId |
  363. *
  364. * Putative ID number.
  365. *
  366. * @parm PJEFFECT * | ppjeff |
  367. *
  368. * Receives pointer to the <t JEFFECT> on success.
  369. *
  370. *****************************************************************************/
  371. HRESULT INTERNAL
  372. CJoyEff_IsValidId(PDJE this, DWORD dwId, PJEFFECT *ppjeff)
  373. {
  374. HRESULT hres;
  375. AssertF(CJoyEff_InCrit(this));
  376. if (dwId) {
  377. PJEFFECT pjeff = &this->rgjeff[dwId - 1];
  378. if (pjeff->fInUse) {
  379. *ppjeff = pjeff;
  380. hres = S_OK;
  381. } else {
  382. hres = E_HANDLE;
  383. }
  384. } else {
  385. hres = E_HANDLE;
  386. }
  387. return hres;
  388. }
  389. /*****************************************************************************
  390. *
  391. * @doc DDK
  392. *
  393. * @method HRESULT | IDirectInputEffectDriver | DeviceID |
  394. *
  395. * Inform the driver of the identity of the device.
  396. *
  397. * For example, if a device driver is passed
  398. * <p dwExternalID> = 2 and <p dwInteralID> = 1,
  399. * then this means that unit 1 on the device
  400. * corresponds to joystick ID number 2.
  401. *
  402. * @cwrap LPDIRECTINPUTEFFECTDRIVER | lpEffectDriver
  403. *
  404. * @parm DWORD | dwDirectInputVersion |
  405. *
  406. * The version of DirectInput that loaded the
  407. * effect driver.
  408. *
  409. * @parm DWORD | dwExternalID |
  410. *
  411. * The joystick ID number being used.
  412. * The Windows joystick subsystem allocates external IDs.
  413. *
  414. * If the <p lpHIDInfo> field is non-<c NULL> then this
  415. * parameter should be ignored.
  416. *
  417. * @parm DWORD | fBegin |
  418. *
  419. * Nonzero if access to the device is beginning.
  420. * Zero if the access to the device is ending.
  421. *
  422. * @parm DWORD | dwInternalID |
  423. *
  424. * Internal joystick id. The device driver manages
  425. * internal IDs.
  426. *
  427. * If the <p lpHIDInfo> field is non-<c NULL> then this
  428. * parameter should be ignored.
  429. *
  430. * @parm LPVOID | lpHIDInfo |
  431. *
  432. * If the underlying device is not a HID device, then this
  433. * parameter is <c NULL>.
  434. *
  435. * If the underlying device is a HID device, then this
  436. * parameter points to a <t DIHIDFFINITINFO> structure
  437. * which informs the driver of HID information.
  438. *
  439. * @returns
  440. *
  441. * <c S_OK> if the operation completed successfully.
  442. *
  443. * An error code if something is wrong.
  444. *
  445. *****************************************************************************/
  446. STDMETHODIMP
  447. CJoyEff_DeviceID(PDED pded, DWORD dwDIVer, DWORD dwExternalID, DWORD fBegin,
  448. DWORD dwInternalID, LPVOID pvReserved)
  449. {
  450. PDJE this;
  451. HRESULT hres;
  452. EnterProcI(IDirectInputEffectDriver::Joy::DeviceID,
  453. (_ "pxuuu", pded, dwDIVer, dwExternalID, fBegin, dwInternalID));
  454. this = _thisPvNm(pded, ded);
  455. dwDIVer;
  456. dwExternalID;
  457. fBegin;
  458. dwInternalID;
  459. pvReserved;
  460. hres = S_OK;
  461. ExitOleProcR();
  462. return hres;
  463. }
  464. /*****************************************************************************
  465. *
  466. * @doc DDK
  467. *
  468. * @method HRESULT | IDirectInputEffectDriver | Escape |
  469. *
  470. * Escape to the driver. This method is called
  471. * in response to an application invoking the
  472. * <mf IDirectInputDevice2::Escape> or
  473. * <mf IDirectInputEffect::Escape> method.
  474. *
  475. * @cwrap LPDIRECTINPUTEFFECTDRIVER | lpEffectDriver
  476. *
  477. * @parm DWORD | dwId |
  478. *
  479. * The joystick ID number being used.
  480. *
  481. * @parm DWORD | dwEffect |
  482. *
  483. * If the application invoked the
  484. * <mf IDirectInputEffect::Escape> method, then
  485. * <p dwEffect> contains the handle (returned by
  486. * <mf IDirectInputEffectDriver::DownloadEffect>)
  487. * of the effect at which the command is directed.
  488. *
  489. * If the application invoked the
  490. * <mf IDirectInputDevice2::Escape> method, then
  491. * <p dwEffect> is zero.
  492. *
  493. * @parm LPDIEFFESCAPE | pesc |
  494. *
  495. * Pointer to a <t DIEFFESCAPE> structure which describes
  496. * the command to be sent. On success, the
  497. * <e DIEFFESCAPE.cbOutBuffer> field contains the number
  498. * of bytes of the output buffer actually used.
  499. *
  500. * DirectInput has already validated that the
  501. * <e DIEFFESCAPE.lpvOutBuffer> and
  502. * <e DIEFFESCAPE.lpvInBuffer> and fields
  503. * point to valid memory.
  504. *
  505. * @returns
  506. *
  507. * <c S_OK> if the operation completed successfully.
  508. *
  509. * An error code if something is wrong.
  510. *
  511. *****************************************************************************/
  512. STDMETHODIMP
  513. CJoyEff_Escape(PDED pded, DWORD dwId, DWORD dwEffect, LPDIEFFESCAPE pesc)
  514. {
  515. PDJE this;
  516. HRESULT hres;
  517. EnterProcI(IDirectInputEffectDriver::Joy::Escape,
  518. (_ "puxx", pded, dwId, dwEffect, pesc->dwCommand));
  519. this = _thisPvNm(pded, ded);
  520. dwId;
  521. dwEffect;
  522. pesc;
  523. hres = E_NOTIMPL;
  524. ExitOleProcR();
  525. return hres;
  526. }
  527. /*****************************************************************************
  528. *
  529. * @doc DDK
  530. *
  531. * @method HRESULT | IDirectInputEffectDriver | SetGain |
  532. *
  533. * Set the overall device gain.
  534. *
  535. * @cwrap LPDIRECTINPUTEFFECTDRIVER | lpEffectDriver
  536. *
  537. * @parm DWORD | dwId |
  538. *
  539. * The joystick ID number being used.
  540. *
  541. * @parm DWORD | dwGain |
  542. *
  543. * The new gain value.
  544. *
  545. * If the value is out of range for the device, the device
  546. * should use the nearest supported value and return
  547. * <c DI_TRUNCATED>.
  548. *
  549. * @returns
  550. *
  551. * <c S_OK> if the operation completed successfully.
  552. *
  553. * An error code if something is wrong.
  554. *
  555. *****************************************************************************/
  556. STDMETHODIMP
  557. CJoyEff_SetGain(PDED pded, DWORD dwId, DWORD dwGain)
  558. {
  559. PDJE this;
  560. HRESULT hres;
  561. EnterProcI(IDirectInputEffectDriver::Joy::SetGain,
  562. (_ "puu", pded, dwId, dwGain));
  563. this = _thisPvNm(pded, ded);
  564. CJoyEff_EnterCrit(this);
  565. dwId;
  566. this->dwGain = dwGain;
  567. CJoyEff_LeaveCrit(this);
  568. hres = S_OK;
  569. ExitOleProcR();
  570. return hres;
  571. }
  572. /*****************************************************************************
  573. *
  574. * @doc DDK
  575. *
  576. * @method HRESULT | IDirectInputEffectDriver | SendForceFeedbackCommand |
  577. *
  578. * Send a command to the device.
  579. *
  580. * @cwrap LPDIRECTINPUTEFFECTDRIVER | lpEffectDriver
  581. *
  582. * @parm DWORD | dwId |
  583. *
  584. * The external joystick number being addressed.
  585. *
  586. * @parm DWORD | dwCommand |
  587. *
  588. * Command, one of the <c DISFFC_*> values.
  589. *
  590. * @returns
  591. * <c S_OK> on success.
  592. *
  593. * @devnote
  594. *
  595. * Semantics unclear.
  596. *
  597. *****************************************************************************/
  598. STDMETHODIMP
  599. CJoyEff_SendForceFeedbackCommand(PDED pded, DWORD dwId, DWORD dwCmd)
  600. {
  601. PDJE this;
  602. HRESULT hres;
  603. EnterProcI(IDirectInputEffectDriver::Joy::SendForceFeedbackCommand,
  604. (_ "pux", pded, dwId, dwCmd));
  605. this = _thisPvNm(pded, ded);
  606. CJoyEff_EnterCrit(this);
  607. dwId;
  608. dwCmd;
  609. this->state = dwCmd;
  610. /*
  611. * On a reset, all effects are destroyed.
  612. */
  613. if (dwCmd & DISFFC_RESET) {
  614. DWORD ijeff;
  615. for (ijeff = 0; ijeff < cjeffMax; ijeff++) {
  616. this->rgjeff[ijeff].fInUse = FALSE;
  617. }
  618. }
  619. CJoyEff_LeaveCrit(this);
  620. hres = S_OK;
  621. ExitOleProcR();
  622. return hres;
  623. }
  624. /*****************************************************************************
  625. *
  626. * @doc DDK
  627. *
  628. * @method HRESULT | IDirectInputEffectDriver | GetForceFeedbackState |
  629. *
  630. * Retrieve the force feedback state for the device.
  631. *
  632. * @cwrap LPDIRECTINPUTEFFECTDRIVER | lpEffectDriver
  633. *
  634. * @parm DWORD | dwId |
  635. *
  636. * The external joystick number being addressed.
  637. *
  638. * @parm LPDEVICESTATE | pds |
  639. *
  640. * Receives device state.
  641. *
  642. * DirectInput will set the <e DIDEVICESTATE.dwSize> field
  643. * to sizeof(DIDEVICESTATE) before calling this method.
  644. * @returns
  645. * <c S_OK> on success.
  646. *
  647. * @devnote
  648. *
  649. * Semantics unclear.
  650. *
  651. *****************************************************************************/
  652. STDMETHODIMP
  653. CJoyEff_GetForceFeedbackState(PDED pded, DWORD dwId, LPDIDEVICESTATE pds)
  654. {
  655. PDJE this;
  656. HRESULT hres;
  657. DWORD ijeff, cjeff, cjeffPlaying;
  658. EnterProcI(IDirectInputEffectDriver::Joy::GetForceFeedbackState,
  659. (_ "pup", pded, dwId, pds));
  660. this = _thisPvNm(pded, ded);
  661. dwId;
  662. pds;
  663. if (pds->dwSize == cbX(*pds)) {
  664. CJoyEff_EnterCrit(this);
  665. /*
  666. * Count how many effects are in use, and return it as a percentage.
  667. */
  668. cjeff = cjeffPlaying = 0;
  669. for (ijeff = 0; ijeff < cjeffMax; ijeff++) {
  670. PJEFFECT pjeff = &this->rgjeff[ijeff];
  671. if (pjeff->fInUse) {
  672. cjeff++;
  673. if (pjeff->tmStart &&
  674. GetTickCount() - pjeff->tmStart < pjeff->tmDuration) {
  675. cjeffPlaying++;
  676. }
  677. }
  678. }
  679. pds->dwLoad = MulDiv(100, cjeff, cjeffMax);
  680. /*
  681. * If there are no effects downloaded, then we are empty.
  682. */
  683. pds->dwState = 0;
  684. if (cjeff == 0) {
  685. pds->dwState |= DIGFFS_EMPTY;
  686. } else
  687. /*
  688. * If there are no effects playing, then we are stopped.
  689. */
  690. if (cjeffPlaying == 0) {
  691. pds->dwState |= DIGFFS_STOPPED;
  692. }
  693. /*
  694. * Actuators are always on (dumb fake hardware)
  695. */
  696. pds->dwState |= DIGFFS_ACTUATORSON;
  697. CJoyEff_LeaveCrit(this);
  698. hres = S_OK;
  699. } else {
  700. hres = E_INVALIDARG;
  701. }
  702. ExitOleProcR();
  703. return hres;
  704. }
  705. /*****************************************************************************
  706. *
  707. * @doc DDK
  708. *
  709. * @method HRESULT | IDirectInputEffectDriver | DownloadEffect |
  710. *
  711. * Send an effect to the device.
  712. *
  713. * @cwrap LPDIRECTINPUTEFFECTDRIVER | lpEffectDriver
  714. *
  715. * @parm DWORD | dwId |
  716. *
  717. * The external joystick number being addressed.
  718. *
  719. * @parm DWORD | dwEffectId |
  720. *
  721. * Internal identifier for the effect, taken from
  722. * the <t DIEFFECTATTRIBUTES> structure for the effect
  723. * as stored in the registry.
  724. *
  725. * @parm IN OUT LPDWORD | pdwEffect |
  726. *
  727. * On entry, contains the handle of the effect being
  728. * downloaded. If the value is zero, then a new effect
  729. * is downloaded. If the value is nonzero, then an
  730. * existing effect is modified.
  731. *
  732. * On exit, contains the new effect handle.
  733. *
  734. * On failure, set to zero if the effect is lost,
  735. * or left alone if the effect is still valid with
  736. * its old parameters.
  737. *
  738. * Note that zero is never a valid effect handle.
  739. *
  740. *
  741. * @parm LPCDIEFFECT | peff |
  742. *
  743. * The new parameters for the effect. The axis and button
  744. * values have been converted to object identifiers
  745. * as follows:
  746. *
  747. * - One type specifier:
  748. * <c DIDFT_RELAXIS>,
  749. * <c DIDFT_ABSAXIS>,
  750. * <c DIDFT_PSHBUTTON>,
  751. * <c DIDFT_TGLBUTTON>,
  752. * <c DIDFT_POV>.
  753. *
  754. * - One instance specifier:
  755. * <c DIDFT_MAKEINSTANCE>(n).
  756. *
  757. * Other bits are reserved and should be ignored.
  758. *
  759. * For example, the value 0x0200104 corresponds to
  760. * the type specifier <c DIDFT_PSHBUTTON> and
  761. * the instance specifier <c DIDFT_MAKEINSTANCE>(1),
  762. * which together indicate that the effect should
  763. * be associated with button 1. Axes, buttons, and POVs
  764. * are each numbered starting from zero.
  765. *
  766. * @parm DWORD | dwFlags |
  767. *
  768. * Zero or more <c DIEP_*> flags specifying which
  769. * portions of the effect information has changed from
  770. * the effect already on the device.
  771. *
  772. * This information is passed to drivers to allow for
  773. * optimization of effect modification. If an effect
  774. * is being modified, a driver may be able to update
  775. * the effect <y in situ> and transmit to the device
  776. * only the information that has changed.
  777. *
  778. * Drivers are not, however, required to implement this
  779. * optimization. All fields in the <t DIEFFECT> structure
  780. * pointed to by the <p peff> parameter are valid, and
  781. * a driver may choose simply to update all parameters of
  782. * the effect at each download.
  783. *
  784. * @returns
  785. * <c S_OK> on success.
  786. *
  787. * @devnote
  788. *
  789. * This implies that 0 is never a valid effect handle value.
  790. *
  791. *****************************************************************************/
  792. STDMETHODIMP
  793. CJoyEff_DownloadEffect(PDED pded, DWORD dwId, DWORD dwEffectId,
  794. LPDWORD pdwEffect, LPCDIEFFECT peff, DWORD fl)
  795. {
  796. PDJE this;
  797. HRESULT hres;
  798. EnterProcI(IDirectInputEffectDriver::Joy::DownloadEffect,
  799. (_ "puxxpx", pded, dwId, dwEffectId, *pdwEffect, peff, fl));
  800. this = _thisPvNm(pded, ded);
  801. CJoyEff_EnterCrit(this);
  802. dwId;
  803. fl;
  804. if (dwEffectId == 1) {
  805. PJEFFECT pjeff;
  806. DWORD dwGain;
  807. /*
  808. * Parameter validation goes here, if any.
  809. *
  810. * Envelope parameter is ignored.
  811. */
  812. if (peff->cAxes == 0) { /* Zero axes? Nice try */
  813. hres = E_INVALIDARG;
  814. goto done;
  815. }
  816. /*
  817. * Pin above-nominal values to DI_FFNOMINALMAX because
  818. * we don't support overgain.
  819. */
  820. dwGain = min(peff->dwGain, DI_FFNOMINALMAX);
  821. /*
  822. * We do not support triggers.
  823. */
  824. if (peff->dwTriggerButton != DIEB_NOTRIGGER) {
  825. hres = E_NOTIMPL;
  826. goto done;
  827. }
  828. /*
  829. * If no downloading in effect, then we're done.
  830. */
  831. if (fl & DIEP_NODOWNLOAD) {
  832. hres = S_OK;
  833. goto done;
  834. }
  835. if (*pdwEffect) {
  836. hres = CJoyEff_IsValidId(this, *pdwEffect, &pjeff);
  837. if (FAILED(hres)) {
  838. goto done;
  839. }
  840. } else {
  841. DWORD ijeff;
  842. for (ijeff = 0; ijeff < cjeffMax; ijeff++) {
  843. if (!this->rgjeff[ijeff].fInUse) {
  844. this->rgjeff[ijeff].fInUse = TRUE;
  845. pjeff = &this->rgjeff[ijeff];
  846. goto haveEffect;
  847. }
  848. }
  849. hres = DIERR_DEVICEFULL;
  850. goto done;
  851. }
  852. haveEffect:;
  853. SquirtSqflPtszV(sqfl, TEXT("dwFlags=%08x"), peff->dwFlags);
  854. SquirtSqflPtszV(sqfl, TEXT("cAxes=%d"), peff->cAxes);
  855. for (fl = 0; fl < peff->cAxes; fl++) {
  856. SquirtSqflPtszV(sqfl, TEXT(" Axis%2d=%08x Direction=%5d"),
  857. fl, peff->rgdwAxes[fl],
  858. peff->rglDirection[fl]);
  859. }
  860. SquirtSqflPtszV(sqfl, TEXT("dwTrigger=%08x"), peff->dwTriggerButton);
  861. pjeff->tmDuration = peff->dwDuration / 1000;
  862. *pdwEffect = (DWORD)(pjeff - this->rgjeff) + 1; //we are sure this cast will not cause problem
  863. hres = S_OK;
  864. } else {
  865. hres = E_NOTIMPL;
  866. }
  867. done:;
  868. CJoyEff_LeaveCrit(this);
  869. ExitOleProc();
  870. return hres;
  871. }
  872. /*****************************************************************************
  873. *
  874. * @doc DDK
  875. *
  876. * @method HRESULT | IDirectInputEffectDriver | DestroyEffect |
  877. *
  878. * Remove an effect from the device.
  879. *
  880. * If the effect is playing, the driver should stop it
  881. * before unloading it.
  882. *
  883. * @cwrap LPDIRECTINPUTEFFECTDRIVER | lpEffectDriver
  884. *
  885. * @parm DWORD | dwId |
  886. *
  887. * The external joystick number being addressed.
  888. *
  889. * @parm DWORD | dwEffect |
  890. *
  891. * The effect to be destroyed.
  892. *
  893. * @returns
  894. * <c S_OK> on success.
  895. *
  896. *****************************************************************************/
  897. STDMETHODIMP
  898. CJoyEff_DestroyEffect(PDED pded, DWORD dwId, DWORD dwEffect)
  899. {
  900. PDJE this;
  901. PJEFFECT pjeff;
  902. HRESULT hres;
  903. EnterProcI(IDirectInputEffectDriver::Joy::DestroyEffect,
  904. (_ "pux", pded, dwId, dwEffect));
  905. this = _thisPvNm(pded, ded);
  906. CJoyEff_EnterCrit(this);
  907. dwId;
  908. hres = CJoyEff_IsValidId(this, dwEffect, &pjeff);
  909. if (SUCCEEDED(hres)) {
  910. pjeff->fInUse = 0;
  911. }
  912. CJoyEff_LeaveCrit(this);
  913. ExitOleProcR();
  914. return hres;
  915. }
  916. /*****************************************************************************
  917. *
  918. * @doc DDK
  919. *
  920. * @method HRESULT | IDirectInputEffectDriver | StartEffect |
  921. *
  922. * Begin playback of an effect.
  923. *
  924. * If the effect is already playing, then it is restarted
  925. * from the beginning.
  926. *
  927. * @cwrap LPDIRECTINPUTEFFECTDRIVER | lpEffectDriver
  928. *
  929. * @parm DWORD | dwId |
  930. *
  931. * The external joystick number being addressed.
  932. *
  933. * @parm DWORD | dwEffect |
  934. *
  935. * The effect to be played.
  936. *
  937. * @parm DWORD | dwMode |
  938. *
  939. * How the effect is to affect other effects.
  940. *
  941. * This parameter consists of zero or more
  942. * <c DIES_*> flags. Note, however, that the driver
  943. * will never receive the <c DIES_NODOWNLOAD> flag;
  944. * the <c DIES_NODOWNLOAD> flag is managed by
  945. * DirectInput and not the driver.
  946. *
  947. * @parm DWORD | dwCount |
  948. *
  949. * Number of times the effect is to be played.
  950. *
  951. * @returns
  952. * <c S_OK> on success.
  953. *
  954. *****************************************************************************/
  955. STDMETHODIMP
  956. CJoyEff_StartEffect(PDED pded, DWORD dwId, DWORD dwEffect,
  957. DWORD dwMode, DWORD dwCount)
  958. {
  959. PDJE this;
  960. PJEFFECT pjeff;
  961. HRESULT hres;
  962. EnterProcI(IDirectInputEffectDriver::Joy::StartEffect,
  963. (_ "puxxu", pded, dwId, dwEffect, dwMode, dwCount));
  964. this = _thisPvNm(pded, ded);
  965. CJoyEff_EnterCrit(this);
  966. dwId;
  967. hres = CJoyEff_IsValidId(this, dwEffect, &pjeff);
  968. if (SUCCEEDED(hres)) {
  969. if (pjeff->tmStart) {
  970. if (GetTickCount() - pjeff->tmStart < pjeff->tmDuration) {
  971. /* Already playing */
  972. hres = hresLe(ERROR_BUSY);
  973. } else {
  974. pjeff->tmStart = GetTickCount();
  975. hres = S_OK;
  976. }
  977. } else {
  978. pjeff->tmStart = GetTickCount();
  979. hres = S_OK;
  980. }
  981. }
  982. CJoyEff_LeaveCrit(this);
  983. ExitOleProcR();
  984. return hres;
  985. }
  986. /*****************************************************************************
  987. *
  988. * @doc DDK
  989. *
  990. * @method HRESULT | IDirectInputEffectDriver | StopEffect |
  991. *
  992. * Halt playback of an effect.
  993. *
  994. * @cwrap LPDIRECTINPUTEFFECTDRIVER | lpEffectDriver
  995. *
  996. * @parm DWORD | dwId |
  997. *
  998. * The external joystick number being addressed.
  999. *
  1000. * @parm DWORD | dwEffect |
  1001. *
  1002. * The effect to be stopped.
  1003. *
  1004. * @returns
  1005. * <c S_OK> on success.
  1006. *
  1007. *****************************************************************************/
  1008. STDMETHODIMP
  1009. CJoyEff_StopEffect(PDED pded, DWORD dwId, DWORD dwEffect)
  1010. {
  1011. PDJE this;
  1012. PJEFFECT pjeff;
  1013. HRESULT hres;
  1014. EnterProcI(IDirectInputEffectDriver::Joy::StopEffect,
  1015. (_ "pux", pded, dwId, dwEffect));
  1016. this = _thisPvNm(pded, ded);
  1017. CJoyEff_EnterCrit(this);
  1018. dwId;
  1019. hres = CJoyEff_IsValidId(this, dwEffect, &pjeff);
  1020. if (SUCCEEDED(hres)) {
  1021. if (pjeff->tmStart) {
  1022. if (GetTickCount() - pjeff->tmStart < pjeff->tmDuration) {
  1023. /* It is still playing; stop it */
  1024. hres = S_OK;
  1025. } else {
  1026. hres = S_FALSE; /* It already stopped on its own */
  1027. }
  1028. pjeff->tmStart = 0;
  1029. } else {
  1030. hres = S_FALSE; /* It was never started */
  1031. }
  1032. }
  1033. CJoyEff_LeaveCrit(this);
  1034. ExitOleProcR();
  1035. return hres;
  1036. }
  1037. /*****************************************************************************
  1038. *
  1039. * @doc DDK
  1040. *
  1041. * @method HRESULT | IDirectInputEffectDriver | GetEffectStatus |
  1042. *
  1043. * Obtain information about an effect.
  1044. *
  1045. * @cwrap LPDIRECTINPUTEFFECTDRIVER | lpEffectDriver
  1046. *
  1047. * @parm DWORD | dwId |
  1048. *
  1049. * The external joystick number being addressed.
  1050. *
  1051. * @parm DWORD | dwEffect |
  1052. *
  1053. * The effect to be queried.
  1054. *
  1055. * @parm LPDWORD | pdwStatus |
  1056. *
  1057. * Receives the effect status.
  1058. *
  1059. * @returns
  1060. * <c S_OK> on success.
  1061. *
  1062. *****************************************************************************/
  1063. STDMETHODIMP
  1064. CJoyEff_GetEffectStatus(PDED pded, DWORD dwId, DWORD dwEffect,
  1065. LPDWORD pdwStatus)
  1066. {
  1067. PDJE this;
  1068. PJEFFECT pjeff;
  1069. HRESULT hres;
  1070. EnterProcI(IDirectInputEffectDriver::Joy::StopEffect,
  1071. (_ "pux", pded, dwId, dwEffect));
  1072. this = _thisPvNm(pded, ded);
  1073. CJoyEff_EnterCrit(this);
  1074. dwId;
  1075. hres = CJoyEff_IsValidId(this, dwEffect, &pjeff);
  1076. if (SUCCEEDED(hres)) {
  1077. DWORD dwStatus;
  1078. dwStatus = 0;
  1079. if (pjeff->tmStart &&
  1080. GetTickCount() - pjeff->tmStart < pjeff->tmDuration) {
  1081. dwStatus |= DEV_STS_EFFECT_RUNNING;
  1082. }
  1083. *pdwStatus = dwStatus;
  1084. hres = S_OK;
  1085. }
  1086. CJoyEff_LeaveCrit(this);
  1087. ExitOleProcR();
  1088. return hres;
  1089. }
  1090. /*****************************************************************************
  1091. *
  1092. * @doc DDK
  1093. *
  1094. * @method HRESULT | IDirectInputEffectDriver | GetVersions |
  1095. *
  1096. * Obtain version information about the force feedback
  1097. * hardware and driver.
  1098. *
  1099. * @cwrap LPDIRECTINPUTEFFECTDRIVER | lpEffectDriver
  1100. *
  1101. * @parm LPDIDRIVERVERSIONS | pvers |
  1102. *
  1103. * A structure which should be filled in with version information
  1104. * describing the hardware, firmware, and driver.
  1105. *
  1106. * DirectInput will set the <e DIDRIVERVERSIONS.dwSize> field
  1107. * to sizeof(DIDRIVERVERSIONS) before calling this method.
  1108. *
  1109. * @returns
  1110. * <c S_OK> on success.
  1111. *
  1112. *****************************************************************************/
  1113. STDMETHODIMP
  1114. CJoyEff_GetVersions(PDED pded, LPDIDRIVERVERSIONS pvers)
  1115. {
  1116. PDJE this;
  1117. HRESULT hres;
  1118. EnterProcI(IDirectInputEffectDriver::Joy::GetVersions, (_ "pux", pded));
  1119. this = _thisPvNm(pded, ded);
  1120. /*
  1121. * Returning E_NOTIMPL causes DirectInput to ask the VxD for the same
  1122. * information.
  1123. */
  1124. hres = E_NOTIMPL;
  1125. ExitOleProcR();
  1126. return hres;
  1127. }
  1128. /*****************************************************************************
  1129. *
  1130. * CJoyEff_New (constructor)
  1131. *
  1132. *****************************************************************************/
  1133. STDMETHODIMP
  1134. CJoyEff_New(PUNK punkOuter, RIID riid, PPV ppvObj)
  1135. {
  1136. HRESULT hres;
  1137. EnterProcI(IDirectInputEffectDriver::Joy::<constructor>,
  1138. (_ "Gp", riid, ppvObj));
  1139. hres = Common_NewRiid(CJoyEff, punkOuter, riid, ppvObj);
  1140. if (SUCCEEDED(hres)) {
  1141. /* Must use _thisPv if multiple interfaces supported */
  1142. PDJE this = _thisPvNm(*ppvObj, ded);
  1143. /*
  1144. * The critical section must be the very first thing we do,
  1145. * because only Finalize checks for its existence.
  1146. *
  1147. * (We might be finalized without being initialized if the user
  1148. * passed a bogus interface to CJoyEff_New.)
  1149. */
  1150. this->fCritInited = fInitializeCriticalSection(&this->crst);
  1151. if( !this->fCritInited )
  1152. {
  1153. Common_Unhold(this);
  1154. *ppvObj = NULL;
  1155. hres = E_OUTOFMEMORY;
  1156. }
  1157. }
  1158. ExitOleProcPpvR(ppvObj);
  1159. return hres;
  1160. }
  1161. /*****************************************************************************
  1162. *
  1163. * The long-awaited vtbls and templates
  1164. *
  1165. *****************************************************************************/
  1166. #pragma BEGIN_CONST_DATA
  1167. #define CJoyEff_Signature 0x4645454B /* "JEFF" */
  1168. Interface_Template_Begin(CJoyEff)
  1169. Primary_Interface_Template(CJoyEff, IDirectInputEffectDriver)
  1170. Interface_Template_End(CJoyEff)
  1171. Primary_Interface_Begin(CJoyEff, IDirectInputEffectDriver)
  1172. CJoyEff_DeviceID,
  1173. CJoyEff_GetVersions,
  1174. CJoyEff_Escape,
  1175. CJoyEff_SetGain,
  1176. CJoyEff_SendForceFeedbackCommand,
  1177. CJoyEff_GetForceFeedbackState,
  1178. CJoyEff_DownloadEffect,
  1179. CJoyEff_DestroyEffect,
  1180. CJoyEff_StartEffect,
  1181. CJoyEff_StopEffect,
  1182. CJoyEff_GetEffectStatus,
  1183. Primary_Interface_End(CJoyEff, IDirectInputEffectDriver)
  1184. #endif