Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1340 lines
35 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. #ifdef 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 IDirectInputDevice8::Escape> method.
  473. *
  474. * @cwrap LPDIRECTINPUTEFFECTDRIVER | lpEffectDriver
  475. *
  476. * @parm DWORD | dwId |
  477. *
  478. * The joystick ID number being used.
  479. *
  480. * @parm DWORD | dwEffect |
  481. *
  482. * If the application invoked the
  483. * <mf IDirectInputEffect::Escape> method, then
  484. * <p dwEffect> contains the handle (returned by
  485. * <mf IDirectInputEffectDriver::DownloadEffect>)
  486. * of the effect at which the command is directed.
  487. *
  488. * If the application invoked the
  489. * <mf IDirectInputDevice8::Escape> method, then
  490. * <p dwEffect> is zero.
  491. *
  492. * @parm LPDIEFFESCAPE | pesc |
  493. *
  494. * Pointer to a <t DIEFFESCAPE> structure which describes
  495. * the command to be sent. On success, the
  496. * <e DIEFFESCAPE.cbOutBuffer> field contains the number
  497. * of bytes of the output buffer actually used.
  498. *
  499. * DirectInput has already validated that the
  500. * <e DIEFFESCAPE.lpvOutBuffer> and
  501. * <e DIEFFESCAPE.lpvInBuffer> and fields
  502. * point to valid memory.
  503. *
  504. * @returns
  505. *
  506. * <c S_OK> if the operation completed successfully.
  507. *
  508. * An error code if something is wrong.
  509. *
  510. *****************************************************************************/
  511. STDMETHODIMP
  512. CJoyEff_Escape(PDED pded, DWORD dwId, DWORD dwEffect, LPDIEFFESCAPE pesc)
  513. {
  514. PDJE this;
  515. HRESULT hres;
  516. EnterProcI(IDirectInputEffectDriver::Joy::Escape,
  517. (_ "puxx", pded, dwId, dwEffect, pesc->dwCommand));
  518. this = _thisPvNm(pded, ded);
  519. dwId;
  520. dwEffect;
  521. pesc;
  522. hres = E_NOTIMPL;
  523. ExitOleProcR();
  524. return hres;
  525. }
  526. /*****************************************************************************
  527. *
  528. * @doc DDK
  529. *
  530. * @method HRESULT | IDirectInputEffectDriver | SetGain |
  531. *
  532. * Set the overall device gain.
  533. *
  534. * @cwrap LPDIRECTINPUTEFFECTDRIVER | lpEffectDriver
  535. *
  536. * @parm DWORD | dwId |
  537. *
  538. * The joystick ID number being used.
  539. *
  540. * @parm DWORD | dwGain |
  541. *
  542. * The new gain value.
  543. *
  544. * If the value is out of range for the device, the device
  545. * should use the nearest supported value and return
  546. * <c DI_TRUNCATED>.
  547. *
  548. * @returns
  549. *
  550. * <c S_OK> if the operation completed successfully.
  551. *
  552. * An error code if something is wrong.
  553. *
  554. *****************************************************************************/
  555. STDMETHODIMP
  556. CJoyEff_SetGain(PDED pded, DWORD dwId, DWORD dwGain)
  557. {
  558. PDJE this;
  559. HRESULT hres;
  560. EnterProcI(IDirectInputEffectDriver::Joy::SetGain,
  561. (_ "puu", pded, dwId, dwGain));
  562. this = _thisPvNm(pded, ded);
  563. CJoyEff_EnterCrit(this);
  564. dwId;
  565. this->dwGain = dwGain;
  566. CJoyEff_LeaveCrit(this);
  567. hres = S_OK;
  568. ExitOleProcR();
  569. return hres;
  570. }
  571. /*****************************************************************************
  572. *
  573. * @doc DDK
  574. *
  575. * @method HRESULT | IDirectInputEffectDriver | SendForceFeedbackCommand |
  576. *
  577. * Send a command to the device.
  578. *
  579. * @cwrap LPDIRECTINPUTEFFECTDRIVER | lpEffectDriver
  580. *
  581. * @parm DWORD | dwId |
  582. *
  583. * The external joystick number being addressed.
  584. *
  585. * @parm DWORD | dwCommand |
  586. *
  587. * Command, one of the <c DISFFC_*> values.
  588. *
  589. * @returns
  590. * <c S_OK> on success.
  591. *
  592. * @devnote
  593. *
  594. * Semantics unclear.
  595. *
  596. *****************************************************************************/
  597. STDMETHODIMP
  598. CJoyEff_SendForceFeedbackCommand(PDED pded, DWORD dwId, DWORD dwCmd)
  599. {
  600. PDJE this;
  601. HRESULT hres;
  602. EnterProcI(IDirectInputEffectDriver::Joy::SendForceFeedbackCommand,
  603. (_ "pux", pded, dwId, dwCmd));
  604. this = _thisPvNm(pded, ded);
  605. CJoyEff_EnterCrit(this);
  606. dwId;
  607. dwCmd;
  608. this->state = dwCmd;
  609. /*
  610. * On a reset, all effects are destroyed.
  611. */
  612. if (dwCmd & DISFFC_RESET) {
  613. DWORD ijeff;
  614. for (ijeff = 0; ijeff < cjeffMax; ijeff++) {
  615. this->rgjeff[ijeff].fInUse = FALSE;
  616. }
  617. }
  618. CJoyEff_LeaveCrit(this);
  619. hres = S_OK;
  620. ExitOleProcR();
  621. return hres;
  622. }
  623. /*****************************************************************************
  624. *
  625. * @doc DDK
  626. *
  627. * @method HRESULT | IDirectInputEffectDriver | GetForceFeedbackState |
  628. *
  629. * Retrieve the force feedback state for the device.
  630. *
  631. * @cwrap LPDIRECTINPUTEFFECTDRIVER | lpEffectDriver
  632. *
  633. * @parm DWORD | dwId |
  634. *
  635. * The external joystick number being addressed.
  636. *
  637. * @parm LPDEVICESTATE | pds |
  638. *
  639. * Receives device state.
  640. *
  641. * DirectInput will set the <e DIDEVICESTATE.dwSize> field
  642. * to sizeof(DIDEVICESTATE) before calling this method.
  643. * @returns
  644. * <c S_OK> on success.
  645. *
  646. * @devnote
  647. *
  648. * Semantics unclear.
  649. *
  650. *****************************************************************************/
  651. STDMETHODIMP
  652. CJoyEff_GetForceFeedbackState(PDED pded, DWORD dwId, LPDIDEVICESTATE pds)
  653. {
  654. PDJE this;
  655. HRESULT hres;
  656. DWORD ijeff, cjeff, cjeffPlaying;
  657. EnterProcI(IDirectInputEffectDriver::Joy::GetForceFeedbackState,
  658. (_ "pup", pded, dwId, pds));
  659. this = _thisPvNm(pded, ded);
  660. dwId;
  661. pds;
  662. if (pds->dwSize == cbX(*pds)) {
  663. CJoyEff_EnterCrit(this);
  664. /*
  665. * Count how many effects are in use, and return it as a percentage.
  666. */
  667. cjeff = cjeffPlaying = 0;
  668. for (ijeff = 0; ijeff < cjeffMax; ijeff++) {
  669. PJEFFECT pjeff = &this->rgjeff[ijeff];
  670. if (pjeff->fInUse) {
  671. cjeff++;
  672. if (pjeff->tmStart &&
  673. GetTickCount() - pjeff->tmStart < pjeff->tmDuration) {
  674. cjeffPlaying++;
  675. }
  676. }
  677. }
  678. pds->dwLoad = MulDiv(100, cjeff, cjeffMax);
  679. /*
  680. * If there are no effects downloaded, then we are empty.
  681. */
  682. pds->dwState = 0;
  683. if (cjeff == 0) {
  684. pds->dwState |= DIGFFS_EMPTY;
  685. } else
  686. /*
  687. * If there are no effects playing, then we are stopped.
  688. */
  689. if (cjeffPlaying == 0) {
  690. pds->dwState |= DIGFFS_STOPPED;
  691. }
  692. /*
  693. * Actuators are always on (dumb fake hardware)
  694. */
  695. pds->dwState |= DIGFFS_ACTUATORSON;
  696. CJoyEff_LeaveCrit(this);
  697. hres = S_OK;
  698. } else {
  699. hres = E_INVALIDARG;
  700. }
  701. ExitOleProcR();
  702. return hres;
  703. }
  704. /*****************************************************************************
  705. *
  706. * @doc DDK
  707. *
  708. * @method HRESULT | IDirectInputEffectDriver | DownloadEffect |
  709. *
  710. * Send an effect to the device.
  711. *
  712. * @cwrap LPDIRECTINPUTEFFECTDRIVER | lpEffectDriver
  713. *
  714. * @parm DWORD | dwId |
  715. *
  716. * The external joystick number being addressed.
  717. *
  718. * @parm DWORD | dwEffectId |
  719. *
  720. * Internal identifier for the effect, taken from
  721. * the <t DIEFFECTATTRIBUTES> structure for the effect
  722. * as stored in the registry.
  723. *
  724. * @parm IN OUT LPDWORD | pdwEffect |
  725. *
  726. * On entry, contains the handle of the effect being
  727. * downloaded. If the value is zero, then a new effect
  728. * is downloaded. If the value is nonzero, then an
  729. * existing effect is modified.
  730. *
  731. * On exit, contains the new effect handle.
  732. *
  733. * On failure, set to zero if the effect is lost,
  734. * or left alone if the effect is still valid with
  735. * its old parameters.
  736. *
  737. * Note that zero is never a valid effect handle.
  738. *
  739. *
  740. * @parm LPCDIEFFECT | peff |
  741. *
  742. * The new parameters for the effect. The axis and button
  743. * values have been converted to object identifiers
  744. * as follows:
  745. *
  746. * - One type specifier:
  747. * <c DIDFT_RELAXIS>,
  748. * <c DIDFT_ABSAXIS>,
  749. * <c DIDFT_PSHBUTTON>,
  750. * <c DIDFT_TGLBUTTON>,
  751. * <c DIDFT_POV>.
  752. *
  753. * - One instance specifier:
  754. * <c DIDFT_MAKEINSTANCE>(n).
  755. *
  756. * Other bits are reserved and should be ignored.
  757. *
  758. * For example, the value 0x0200104 corresponds to
  759. * the type specifier <c DIDFT_PSHBUTTON> and
  760. * the instance specifier <c DIDFT_MAKEINSTANCE>(1),
  761. * which together indicate that the effect should
  762. * be associated with button 1. Axes, buttons, and POVs
  763. * are each numbered starting from zero.
  764. *
  765. * @parm DWORD | dwFlags |
  766. *
  767. * Zero or more <c DIEP_*> flags specifying which
  768. * portions of the effect information has changed from
  769. * the effect already on the device.
  770. *
  771. * This information is passed to drivers to allow for
  772. * optimization of effect modification. If an effect
  773. * is being modified, a driver may be able to update
  774. * the effect <y in situ> and transmit to the device
  775. * only the information that has changed.
  776. *
  777. * Drivers are not, however, required to implement this
  778. * optimization. All fields in the <t DIEFFECT> structure
  779. * pointed to by the <p peff> parameter are valid, and
  780. * a driver may choose simply to update all parameters of
  781. * the effect at each download.
  782. *
  783. * @returns
  784. * <c S_OK> on success.
  785. *
  786. * @devnote
  787. *
  788. * This implies that 0 is never a valid effect handle value.
  789. *
  790. *****************************************************************************/
  791. STDMETHODIMP
  792. CJoyEff_DownloadEffect(PDED pded, DWORD dwId, DWORD dwEffectId,
  793. LPDWORD pdwEffect, LPCDIEFFECT peff, DWORD fl)
  794. {
  795. PDJE this;
  796. HRESULT hres;
  797. EnterProcI(IDirectInputEffectDriver::Joy::DownloadEffect,
  798. (_ "puxxpx", pded, dwId, dwEffectId, *pdwEffect, peff, fl));
  799. this = _thisPvNm(pded, ded);
  800. CJoyEff_EnterCrit(this);
  801. dwId;
  802. fl;
  803. if (dwEffectId == 1) {
  804. PJEFFECT pjeff;
  805. DWORD dwGain;
  806. /*
  807. * Parameter validation goes here, if any.
  808. *
  809. * Envelope parameter is ignored.
  810. */
  811. if (peff->cAxes == 0) { /* Zero axes? Nice try */
  812. hres = E_INVALIDARG;
  813. goto done;
  814. }
  815. /*
  816. * Pin above-nominal values to DI_FFNOMINALMAX because
  817. * we don't support overgain.
  818. */
  819. dwGain = min(peff->dwGain, DI_FFNOMINALMAX);
  820. /*
  821. * We do not support triggers.
  822. */
  823. if (peff->dwTriggerButton != DIEB_NOTRIGGER) {
  824. hres = E_NOTIMPL;
  825. goto done;
  826. }
  827. /*
  828. * If no downloading in effect, then we're done.
  829. */
  830. if (fl & DIEP_NODOWNLOAD) {
  831. hres = S_OK;
  832. goto done;
  833. }
  834. if (*pdwEffect) {
  835. hres = CJoyEff_IsValidId(this, *pdwEffect, &pjeff);
  836. if (FAILED(hres)) {
  837. goto done;
  838. }
  839. } else {
  840. DWORD ijeff;
  841. for (ijeff = 0; ijeff < cjeffMax; ijeff++) {
  842. if (!this->rgjeff[ijeff].fInUse) {
  843. this->rgjeff[ijeff].fInUse = TRUE;
  844. pjeff = &this->rgjeff[ijeff];
  845. goto haveEffect;
  846. }
  847. }
  848. hres = DIERR_DEVICEFULL;
  849. goto done;
  850. }
  851. haveEffect:;
  852. SquirtSqflPtszV(sqfl, TEXT("dwFlags=%08x"), peff->dwFlags);
  853. SquirtSqflPtszV(sqfl, TEXT("cAxes=%d"), peff->cAxes);
  854. for (fl = 0; fl < peff->cAxes; fl++) {
  855. SquirtSqflPtszV(sqfl, TEXT(" Axis%2d=%08x Direction=%5d"),
  856. fl, peff->rgdwAxes[fl],
  857. peff->rglDirection[fl]);
  858. }
  859. SquirtSqflPtszV(sqfl, TEXT("dwTrigger=%08x"), peff->dwTriggerButton);
  860. pjeff->tmDuration = peff->dwDuration / 1000;
  861. *pdwEffect = (DWORD)(pjeff - this->rgjeff) + 1; //we are sure this cast will not cause problem
  862. hres = S_OK;
  863. } else {
  864. hres = E_NOTIMPL;
  865. }
  866. done:;
  867. CJoyEff_LeaveCrit(this);
  868. ExitOleProc();
  869. return hres;
  870. }
  871. /*****************************************************************************
  872. *
  873. * @doc DDK
  874. *
  875. * @method HRESULT | IDirectInputEffectDriver | DestroyEffect |
  876. *
  877. * Remove an effect from the device.
  878. *
  879. * If the effect is playing, the driver should stop it
  880. * before unloading it.
  881. *
  882. * @cwrap LPDIRECTINPUTEFFECTDRIVER | lpEffectDriver
  883. *
  884. * @parm DWORD | dwId |
  885. *
  886. * The external joystick number being addressed.
  887. *
  888. * @parm DWORD | dwEffect |
  889. *
  890. * The effect to be destroyed.
  891. *
  892. * @returns
  893. * <c S_OK> on success.
  894. *
  895. *****************************************************************************/
  896. STDMETHODIMP
  897. CJoyEff_DestroyEffect(PDED pded, DWORD dwId, DWORD dwEffect)
  898. {
  899. PDJE this;
  900. PJEFFECT pjeff;
  901. HRESULT hres;
  902. EnterProcI(IDirectInputEffectDriver::Joy::DestroyEffect,
  903. (_ "pux", pded, dwId, dwEffect));
  904. this = _thisPvNm(pded, ded);
  905. CJoyEff_EnterCrit(this);
  906. dwId;
  907. hres = CJoyEff_IsValidId(this, dwEffect, &pjeff);
  908. if (SUCCEEDED(hres)) {
  909. pjeff->fInUse = 0;
  910. }
  911. CJoyEff_LeaveCrit(this);
  912. ExitOleProcR();
  913. return hres;
  914. }
  915. /*****************************************************************************
  916. *
  917. * @doc DDK
  918. *
  919. * @method HRESULT | IDirectInputEffectDriver | StartEffect |
  920. *
  921. * Begin playback of an effect.
  922. *
  923. * If the effect is already playing, then it is restarted
  924. * from the beginning.
  925. *
  926. * @cwrap LPDIRECTINPUTEFFECTDRIVER | lpEffectDriver
  927. *
  928. * @parm DWORD | dwId |
  929. *
  930. * The external joystick number being addressed.
  931. *
  932. * @parm DWORD | dwEffect |
  933. *
  934. * The effect to be played.
  935. *
  936. * @parm DWORD | dwMode |
  937. *
  938. * How the effect is to affect other effects.
  939. *
  940. * This parameter consists of zero or more
  941. * <c DIES_*> flags. Note, however, that the driver
  942. * will never receive the <c DIES_NODOWNLOAD> flag;
  943. * the <c DIES_NODOWNLOAD> flag is managed by
  944. * DirectInput and not the driver.
  945. *
  946. * @parm DWORD | dwCount |
  947. *
  948. * Number of times the effect is to be played.
  949. *
  950. * @returns
  951. * <c S_OK> on success.
  952. *
  953. *****************************************************************************/
  954. STDMETHODIMP
  955. CJoyEff_StartEffect(PDED pded, DWORD dwId, DWORD dwEffect,
  956. DWORD dwMode, DWORD dwCount)
  957. {
  958. PDJE this;
  959. PJEFFECT pjeff;
  960. HRESULT hres;
  961. EnterProcI(IDirectInputEffectDriver::Joy::StartEffect,
  962. (_ "puxxu", pded, dwId, dwEffect, dwMode, dwCount));
  963. this = _thisPvNm(pded, ded);
  964. CJoyEff_EnterCrit(this);
  965. dwId;
  966. hres = CJoyEff_IsValidId(this, dwEffect, &pjeff);
  967. if (SUCCEEDED(hres)) {
  968. if (pjeff->tmStart) {
  969. if (GetTickCount() - pjeff->tmStart < pjeff->tmDuration) {
  970. /* Already playing */
  971. hres = hresLe(ERROR_BUSY);
  972. } else {
  973. pjeff->tmStart = GetTickCount();
  974. hres = S_OK;
  975. }
  976. } else {
  977. pjeff->tmStart = GetTickCount();
  978. hres = S_OK;
  979. }
  980. }
  981. CJoyEff_LeaveCrit(this);
  982. ExitOleProcR();
  983. return hres;
  984. }
  985. /*****************************************************************************
  986. *
  987. * @doc DDK
  988. *
  989. * @method HRESULT | IDirectInputEffectDriver | StopEffect |
  990. *
  991. * Halt playback of an effect.
  992. *
  993. * @cwrap LPDIRECTINPUTEFFECTDRIVER | lpEffectDriver
  994. *
  995. * @parm DWORD | dwId |
  996. *
  997. * The external joystick number being addressed.
  998. *
  999. * @parm DWORD | dwEffect |
  1000. *
  1001. * The effect to be stopped.
  1002. *
  1003. * @returns
  1004. * <c S_OK> on success.
  1005. *
  1006. *****************************************************************************/
  1007. STDMETHODIMP
  1008. CJoyEff_StopEffect(PDED pded, DWORD dwId, DWORD dwEffect)
  1009. {
  1010. PDJE this;
  1011. PJEFFECT pjeff;
  1012. HRESULT hres;
  1013. EnterProcI(IDirectInputEffectDriver::Joy::StopEffect,
  1014. (_ "pux", pded, dwId, dwEffect));
  1015. this = _thisPvNm(pded, ded);
  1016. CJoyEff_EnterCrit(this);
  1017. dwId;
  1018. hres = CJoyEff_IsValidId(this, dwEffect, &pjeff);
  1019. if (SUCCEEDED(hres)) {
  1020. if (pjeff->tmStart) {
  1021. if (GetTickCount() - pjeff->tmStart < pjeff->tmDuration) {
  1022. /* It is still playing; stop it */
  1023. hres = S_OK;
  1024. } else {
  1025. hres = S_FALSE; /* It already stopped on its own */
  1026. }
  1027. pjeff->tmStart = 0;
  1028. } else {
  1029. hres = S_FALSE; /* It was never started */
  1030. }
  1031. }
  1032. CJoyEff_LeaveCrit(this);
  1033. ExitOleProcR();
  1034. return hres;
  1035. }
  1036. /*****************************************************************************
  1037. *
  1038. * @doc DDK
  1039. *
  1040. * @method HRESULT | IDirectInputEffectDriver | GetEffectStatus |
  1041. *
  1042. * Obtain information about an effect.
  1043. *
  1044. * @cwrap LPDIRECTINPUTEFFECTDRIVER | lpEffectDriver
  1045. *
  1046. * @parm DWORD | dwId |
  1047. *
  1048. * The external joystick number being addressed.
  1049. *
  1050. * @parm DWORD | dwEffect |
  1051. *
  1052. * The effect to be queried.
  1053. *
  1054. * @parm LPDWORD | pdwStatus |
  1055. *
  1056. * Receives the effect status.
  1057. *
  1058. * @returns
  1059. * <c S_OK> on success.
  1060. *
  1061. *****************************************************************************/
  1062. STDMETHODIMP
  1063. CJoyEff_GetEffectStatus(PDED pded, DWORD dwId, DWORD dwEffect,
  1064. LPDWORD pdwStatus)
  1065. {
  1066. PDJE this;
  1067. PJEFFECT pjeff;
  1068. HRESULT hres;
  1069. EnterProcI(IDirectInputEffectDriver::Joy::StopEffect,
  1070. (_ "pux", pded, dwId, dwEffect));
  1071. this = _thisPvNm(pded, ded);
  1072. CJoyEff_EnterCrit(this);
  1073. dwId;
  1074. hres = CJoyEff_IsValidId(this, dwEffect, &pjeff);
  1075. if (SUCCEEDED(hres)) {
  1076. DWORD dwStatus;
  1077. dwStatus = 0;
  1078. if (pjeff->tmStart &&
  1079. GetTickCount() - pjeff->tmStart < pjeff->tmDuration) {
  1080. dwStatus |= DEV_STS_EFFECT_RUNNING;
  1081. }
  1082. *pdwStatus = dwStatus;
  1083. hres = S_OK;
  1084. }
  1085. CJoyEff_LeaveCrit(this);
  1086. ExitOleProcR();
  1087. return hres;
  1088. }
  1089. /*****************************************************************************
  1090. *
  1091. * @doc DDK
  1092. *
  1093. * @method HRESULT | IDirectInputEffectDriver | GetVersions |
  1094. *
  1095. * Obtain version information about the force feedback
  1096. * hardware and driver.
  1097. *
  1098. * @cwrap LPDIRECTINPUTEFFECTDRIVER | lpEffectDriver
  1099. *
  1100. * @parm LPDIDRIVERVERSIONS | pvers |
  1101. *
  1102. * A structure which should be filled in with version information
  1103. * describing the hardware, firmware, and driver.
  1104. *
  1105. * DirectInput will set the <e DIDRIVERVERSIONS.dwSize> field
  1106. * to sizeof(DIDRIVERVERSIONS) before calling this method.
  1107. *
  1108. * @returns
  1109. * <c S_OK> on success.
  1110. *
  1111. *****************************************************************************/
  1112. STDMETHODIMP
  1113. CJoyEff_GetVersions(PDED pded, LPDIDRIVERVERSIONS pvers)
  1114. {
  1115. PDJE this;
  1116. HRESULT hres;
  1117. EnterProcI(IDirectInputEffectDriver::Joy::GetVersions, (_ "pux", pded));
  1118. this = _thisPvNm(pded, ded);
  1119. /*
  1120. * Returning E_NOTIMPL causes DirectInput to ask the VxD for the same
  1121. * information.
  1122. */
  1123. hres = E_NOTIMPL;
  1124. ExitOleProcR();
  1125. return hres;
  1126. }
  1127. /*****************************************************************************
  1128. *
  1129. * CJoyEff_New (constructor)
  1130. *
  1131. *****************************************************************************/
  1132. STDMETHODIMP
  1133. CJoyEff_New(PUNK punkOuter, RIID riid, PPV ppvObj)
  1134. {
  1135. HRESULT hres;
  1136. EnterProcI(IDirectInputEffectDriver::Joy::<constructor>,
  1137. (_ "Gp", riid, ppvObj));
  1138. hres = Common_NewRiid(CJoyEff, punkOuter, riid, ppvObj);
  1139. if (SUCCEEDED(hres)) {
  1140. /* Must use _thisPv if multiple interfaces supported */
  1141. PDJE this = _thisPvNm(*ppvObj, ded);
  1142. /*
  1143. * The critical section must be the very first thing we do,
  1144. * because only Finalize checks for its existence.
  1145. *
  1146. * (We might be finalized without being initialized if the user
  1147. * passed a bogus interface to CJoyEff_New.)
  1148. */
  1149. this->fCritInited = fInitializeCriticalSection(&this->crst);
  1150. if( !this->fCritInited )
  1151. {
  1152. Common_Unhold(this);
  1153. *ppvObj = NULL;
  1154. hres = E_OUTOFMEMORY;
  1155. }
  1156. }
  1157. ExitOleProcPpvR(ppvObj);
  1158. return hres;
  1159. }
  1160. /*****************************************************************************
  1161. *
  1162. * The long-awaited vtbls and templates
  1163. *
  1164. *****************************************************************************/
  1165. #pragma BEGIN_CONST_DATA
  1166. #define CJoyEff_Signature 0x4645454B /* "JEFF" */
  1167. Interface_Template_Begin(CJoyEff)
  1168. Primary_Interface_Template(CJoyEff, IDirectInputEffectDriver)
  1169. Interface_Template_End(CJoyEff)
  1170. Primary_Interface_Begin(CJoyEff, IDirectInputEffectDriver)
  1171. CJoyEff_DeviceID,
  1172. CJoyEff_GetVersions,
  1173. CJoyEff_Escape,
  1174. CJoyEff_SetGain,
  1175. CJoyEff_SendForceFeedbackCommand,
  1176. CJoyEff_GetForceFeedbackState,
  1177. CJoyEff_DownloadEffect,
  1178. CJoyEff_DestroyEffect,
  1179. CJoyEff_StartEffect,
  1180. CJoyEff_StopEffect,
  1181. CJoyEff_GetEffectStatus,
  1182. Primary_Interface_End(CJoyEff, IDirectInputEffectDriver)
  1183. #endif