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.

1168 lines
37 KiB

  1. // @doc
  2. /**********************************************************************
  3. *
  4. * @module IDirectInputEffectDriver.cpp |
  5. *
  6. * Contains Class Implementation of CIDirectInputEffectDriverClassFactory:
  7. * Factory for Creating Proper Effect Driver
  8. *
  9. * History
  10. * ----------------------------------------------------------
  11. * Matthew L. Coill (mlc) Original Jul-7-1999
  12. *
  13. * (c) 1999 Microsoft Corporation. All right reserved.
  14. *
  15. * @topic This IDirectInputEffectDriver |
  16. * This Driver sits on top of the standard PID driver (which is also
  17. * an IDirectInputEffectDriver) and passes most requests to the PID driver.
  18. * Some requests such as, DownloadEffect and SendForceFeedback command are
  19. * modified for our use. Modification purposes are described at each function
  20. * definition.
  21. *
  22. **********************************************************************/
  23. #include "IDirectInputEffectDriverClassFactory.h"
  24. #include "IDirectInputEffectDriver.h"
  25. #include <WinIOCTL.h> // For CTL_CODE definition
  26. #include "..\\GCKernel.sys\\GckExtrn.h"
  27. #include <crtdbg.h>
  28. #include <objbase.h> // For CoUninitialize
  29. #include <stdio.h>
  30. #include <stdarg.h>
  31. #include <tchar.h>
  32. /*
  33. void __cdecl LogIt(LPCSTR lpszFormat, ...)
  34. {
  35. va_list args;
  36. va_start(args, lpszFormat);
  37. char szBuffer[1024];
  38. FILE* pLogFile = NULL;
  39. pLogFile = fopen("swpidflt.log", "a");
  40. _vsnprintf(szBuffer, sizeof(szBuffer), lpszFormat, args);
  41. fprintf(pLogFile, szBuffer);
  42. va_end(args);
  43. fclose(pLogFile);
  44. }
  45. */
  46. const GUID IID_IDirectInputEffectDriver = {
  47. 0x02538130,
  48. 0x898F,
  49. 0x11D0,
  50. { 0x9A,0xD0,0x00,0xA0,0xC9,0xA0,0x6E,0x35 }
  51. };
  52. extern TCHAR CLSID_SWPIDDriver_String[];
  53. LONG DllAddRef();
  54. LONG DllRelease();
  55. DWORD __stdcall DoWaitForForceSchemeChange(void* pParameter);
  56. const DWORD c_dwShutdownWait = 500; // (0.5 Seconds)
  57. struct DIHIDFFINITINFO_STRUCT {
  58. DWORD dwSize;
  59. LPWSTR pwszDeviceInterface;
  60. GUID GuidInstance;
  61. };
  62. // PID Defines for Effect Tyoes
  63. #define PID_CONSTANT_FORCE 0x26
  64. #define PID_RAMP 0x27
  65. #define PID_SQUARE 0x30
  66. #define PID_SINE 0x31
  67. #define PID_TRIANGLE 0x32
  68. #define PID_SAWTOOTHUP 0x33
  69. #define PID_SAWTOOTHDOWN 0x34
  70. #define PID_SPRING 0x40
  71. #define PID_DAMPER 0x41
  72. #define PID_INTERTIA 0x42
  73. #define PID_FRICTION 0x43
  74. struct PercentageEntry
  75. {
  76. DWORD dwAngle;
  77. DWORD dwPercentageX;
  78. // DWORD dwPercentageY; Y == 10000 - X
  79. };
  80. // Array of Fixed value data
  81. const PercentageEntry g_PercentagesArray[] =
  82. {
  83. // Angle, Sin^2(Angle)
  84. { 0, 0}, // 0 Degrees
  85. { 1125, 381}, // 11.25 Degrees
  86. { 2250, 1465}, // 22.5 Degrees
  87. { 3375, 3087}, // 33.75 Degrees
  88. { 4500, 5000}, // 45 Degrees
  89. { 5625, 6913}, // 56.25 Degrees
  90. { 6750, 8536}, // 67.50 Degrees
  91. { 7875, 9619}, // 78.75 Degrees
  92. { 9000, 10000}, // 90 Degrees
  93. };
  94. const DWORD c_dwTableQuantization = g_PercentagesArray[1].dwAngle;
  95. const LONG c_lContributionY = 2; // (1/2 = 50%)
  96. const BYTE c_bSideWinderPIDReportID_SetEffect = 1;
  97. // Usage Pages (just PID)
  98. const USAGE c_HidUsagePage_PID = 0x0F;
  99. // Usages
  100. const USAGE c_HidUsage_EffectType = 0x25;
  101. const USAGE c_HidUsage_EffectType_Spring = 0x40;
  102. const USAGE c_HidUsage_EffectBlock_Gain = 0x52;
  103. const USAGE c_HidUsage_EffectBlock_Index = 0x22; // This is the ID of the effect
  104. // Preloaded Effects
  105. const BYTE c_EffectID_RTCSpring = 1;
  106. // Local Debugging Streaming Function that works in release
  107. #undef UseMyDebugOut
  108. void __cdecl myDebugOut (LPCSTR lpszFormat, ...)
  109. {
  110. #ifdef UseMyDebugOut
  111. //Stolen from inline void _cdecl AtlTrace(LPCSTR lpszFormat, ...) in AtlBase.h
  112. va_list args;
  113. va_start(args, lpszFormat);
  114. int nBuf;
  115. char szBuffer[1024];
  116. nBuf = _vsnprintf(szBuffer, sizeof(szBuffer), lpszFormat, args);
  117. _ASSERTE(nBuf < sizeof(szBuffer)); //Output truncated as it was > sizeof(szBuffer)
  118. #ifdef _NDEBUG
  119. OutputDebugStringA(szBuffer);
  120. #else
  121. _RPTF0 (_CRT_WARN, szBuffer);
  122. #endif
  123. va_end(args);
  124. #else
  125. UNREFERENCED_PARAMETER (lpszFormat);
  126. return;
  127. #endif
  128. }
  129. /******************** Class CIDirectInputEffectDriver ***********************/
  130. /*****************************************************************************
  131. **
  132. ** CIDirectInputEffectDriverClassFactory::CIDirectInputEffectDriverClassFactory()
  133. **
  134. ** @mfunc Constructor
  135. **
  136. *****************************************************************************/
  137. CIDirectInputEffectDriver::CIDirectInputEffectDriver
  138. (
  139. IDirectInputEffectDriver* pIPIDEffectDriver, //@parm [IN] Pointer to PID Effect Driver
  140. IClassFactory* pIPIDClassFactory //@parm [IN] Pointer to PID Class Factory
  141. ) :
  142. m_ulReferenceCount(1),
  143. m_dwDIVersion(0xFFFFFFFF),
  144. m_dwExternalDeviceID(0xFFFFFFFF),
  145. m_dwInternalDeviceID(0xFFFFFFFF),
  146. m_pIPIDEffectDriver(pIPIDEffectDriver),
  147. m_pIPIDClassFactory(pIPIDClassFactory),
  148. m_hKernelDeviceDriver(NULL),
  149. m_hKernelDeviceDriverDuplicate(NULL),
  150. m_hHidDeviceDriver(NULL),
  151. m_dwGcKernelDevice(0),
  152. m_hForceSchemeChangeWaitThread(NULL),
  153. m_dwForceSchemeChangeThreadID(0),
  154. m_pPreparsedData(NULL)
  155. {
  156. myDebugOut ("CIDirectInputEffectDriver::Constructor (pIPIDEffectDriver:0x%0p)\n", pIPIDEffectDriver);
  157. // Add to gobal object count
  158. DllAddRef();
  159. // Add references for objects we are holding
  160. m_pIPIDClassFactory->AddRef();
  161. m_pIPIDEffectDriver->AddRef();
  162. ::memset((void*)&m_HidAttributes, 0, sizeof(m_HidAttributes));
  163. m_ForceMapping.AssignmentBlock.CommandHeader.eID = eForceMap;
  164. m_ForceMapping.AssignmentBlock.CommandHeader.ulByteSize = sizeof(m_ForceMapping);
  165. m_ForceMapping.AssignmentBlock.ulVidPid = 0; // Irrelevant
  166. m_ForceMapping.bMapYToX = FALSE;
  167. m_ForceMapping.usRTC = 10000;
  168. m_ForceMapping.usGain = 10000;
  169. }
  170. /*****************************************************************************
  171. **
  172. ** CIDirectInputEffectDriver::~CIDirectInputEffectDriver()
  173. **
  174. ** @mfunc Destructor
  175. **
  176. *****************************************************************************/
  177. CIDirectInputEffectDriver::~CIDirectInputEffectDriver()
  178. {
  179. _ASSERTE(m_pIPIDEffectDriver == NULL);
  180. _ASSERTE(m_ulReferenceCount == 0);
  181. DllRelease(); // Remove our object from the global object count
  182. myDebugOut ("CIDirectInputEffectDriver::Destructor\n");
  183. }
  184. //IUnknown members
  185. /***********************************************************************************
  186. **
  187. ** ULONG CIDirectInputEffectDriver::QueryInterface(REFIID refiid, void** ppvObject)
  188. **
  189. ** @func Query an IUnknown for a particular type. This causes reference count increase locally only.
  190. ** If it is a type we don't know, should we give the PID driver a crack (the PID driver
  191. ** might have a customized private interface, we don't want to ruin that). Currently not
  192. ** going to pass on the Query because this could screwup Symmetry.
  193. **
  194. ** @rdesc S_OK : all is well
  195. ** E_INVALIDARG : if (ppvObject == NULL)
  196. ** E_NOINTERFACE : If requested interface is unsupported
  197. **
  198. *************************************************************************************/
  199. HRESULT __stdcall CIDirectInputEffectDriver::QueryInterface
  200. (
  201. REFIID refiid, //@parm [IN] Identifier of the requested interface
  202. void** ppvObject //@parm [OUT] Address to place requested interface pointer
  203. )
  204. {
  205. myDebugOut ("CIDirectInputEffectDriver::QueryInterface (refiid:0x%0p, ppvObject:0x%0p)\n", refiid, ppvObject);
  206. HRESULT hrPidQuery = m_pIPIDEffectDriver->QueryInterface(refiid, ppvObject);
  207. if (SUCCEEDED(hrPidQuery))
  208. {
  209. // Don't perform a real addref (PID.dll::QueryInterface will do its own)
  210. ::InterlockedIncrement((LONG*)&m_ulReferenceCount);
  211. *ppvObject = this;
  212. }
  213. return hrPidQuery;
  214. }
  215. /***********************************************************************************
  216. **
  217. ** ULONG CIDirectInputEffectDriver::AddRef()
  218. **
  219. ** @func Bumps up the reference count
  220. ** The PID driver reference count is left alone. We only decrement it when
  221. ** this object is ready to go away.
  222. **
  223. ** @rdesc New reference count
  224. **
  225. *************************************************************************************/
  226. ULONG __stdcall CIDirectInputEffectDriver::AddRef()
  227. {
  228. myDebugOut ("CIDirectInputEffectDriver::AddRef (Early) 0x%0p\n", m_ulReferenceCount);
  229. m_pIPIDEffectDriver->AddRef();
  230. return (ULONG)(::InterlockedIncrement((LONG*)&m_ulReferenceCount));
  231. }
  232. /***********************************************************************************
  233. **
  234. ** ULONG CIDirectInputEffectDriver::Release()
  235. **
  236. ** @func Decrements the reference count.
  237. ** if the reference count becomes zero this object is destroyed.
  238. ** The PID Factory reference is only effected if it is time to release all.
  239. **
  240. ** @rdesc New reference count
  241. **
  242. *************************************************************************************/
  243. ULONG __stdcall CIDirectInputEffectDriver::Release()
  244. {
  245. myDebugOut ("CIDirectInputEffectDriver::Release (Early) 0x%0p\n", m_ulReferenceCount);
  246. if (m_ulReferenceCount == 0)
  247. {
  248. return m_ulReferenceCount;
  249. }
  250. if ((::InterlockedDecrement((LONG*)&m_ulReferenceCount)) != 0)
  251. {
  252. m_pIPIDEffectDriver->Release();
  253. return m_ulReferenceCount;
  254. }
  255. // Tell the driver to complete outstanding IOCTLs to this device
  256. if (m_hKernelDeviceDriver == NULL)
  257. { // Don't have a handle to PID driver, so open one
  258. m_hKernelDeviceDriver = ::CreateFile(TEXT(GCK_CONTROL_W32Name), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_DELETE_ON_CLOSE, NULL);
  259. if (m_hKernelDeviceDriver == INVALID_HANDLE_VALUE)
  260. {
  261. m_hKernelDeviceDriver = NULL;
  262. }
  263. }
  264. if (m_hKernelDeviceDriver != NULL) // Handle should be open, but check just incase
  265. {
  266. DWORD dwReturnDataSize;
  267. BOOL fSuccess = DeviceIoControl(m_hKernelDeviceDriver,
  268. IOCTL_GCK_END_FF_NOTIFICATION,
  269. (void*)(&m_dwGcKernelDevice), sizeof(DWORD), // In
  270. NULL, 0, &dwReturnDataSize, // Out
  271. NULL);
  272. if (!fSuccess)
  273. myDebugOut ("CIDirectInputEffectDriver::Release : GCK IOCTL_GCK_END_FF_NOTIFICATION failed!\n");
  274. Sleep(c_dwShutdownWait);
  275. ::CloseHandle(m_hKernelDeviceDriver);
  276. }
  277. else
  278. {
  279. myDebugOut ("CIDirectInputEffectDriver::Release : Could not Open GCK for IOCTL_GCK_END_FF_NOTIFICATION\n");
  280. }
  281. // Free up the preparsed data
  282. if (m_pPreparsedData != NULL)
  283. {
  284. ::HidD_FreePreparsedData(m_pPreparsedData);
  285. m_pPreparsedData = NULL;
  286. }
  287. // Close the handle to the HID path of the driver
  288. ::CloseHandle(m_hHidDeviceDriver);
  289. m_hHidDeviceDriver = NULL;
  290. // Close the thread handle (which should be done by now)
  291. if (m_hForceSchemeChangeWaitThread != NULL)
  292. {
  293. ::CloseHandle(m_hForceSchemeChangeWaitThread);
  294. m_hForceSchemeChangeWaitThread = NULL;
  295. m_dwForceSchemeChangeThreadID = 0;
  296. }
  297. else
  298. {
  299. myDebugOut ("CIDirectInputEffectDriver::Release() m_hForceSchemeCHangeWaitThread did not finish!\n");
  300. }
  301. // Release the low level pid driver and delete ourselves
  302. m_pIPIDEffectDriver->Release();
  303. m_pIPIDEffectDriver = NULL;
  304. // Release the low level factory (include extra release to fix bug in PID.dll)
  305. if (m_pIPIDClassFactory->Release() > 0)
  306. {
  307. m_pIPIDClassFactory->Release();
  308. }
  309. m_pIPIDClassFactory = NULL;
  310. delete this;
  311. return 0;
  312. }
  313. //IDirectInputEffectDriver members
  314. HRESULT __stdcall CIDirectInputEffectDriver::DeviceID
  315. (
  316. DWORD dwDIVersion,
  317. DWORD dwExternalID,
  318. DWORD dwIsBegining,
  319. DWORD dwInternalID,
  320. void* pReserved
  321. )
  322. {
  323. myDebugOut ("CIDirectInputEffectDriver::DeviceID (dwDIVersion:0x%08p dwExternalID:0x%08p dwIsBeginning:0x%08p dwInternalID:0x%08p pReserved:0x%08p)\n",
  324. dwDIVersion, dwExternalID, dwIsBegining, dwInternalID, pReserved);
  325. // Store off some data
  326. m_dwExternalDeviceID = dwExternalID;
  327. m_dwInternalDeviceID = dwInternalID;
  328. bool bPossiblyFirstTime = false;
  329. // Get a handle to the Kernel Device and activate the thread
  330. if (m_hKernelDeviceDriver == NULL)
  331. {
  332. bPossiblyFirstTime = true;
  333. m_hKernelDeviceDriver = ::CreateFile(TEXT(GCK_CONTROL_W32Name), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_DELETE_ON_CLOSE, NULL);
  334. if (m_hKernelDeviceDriver == INVALID_HANDLE_VALUE)
  335. {
  336. m_hKernelDeviceDriver = NULL;
  337. myDebugOut ("CIDirectInputEffectDriver::DeviceID Create GCK File Failed!\n");
  338. }
  339. else
  340. {
  341. InitHidInformation((LPDIHIDFFINITINFO)pReserved); // Set up the HID stuff (preparsed data et al)
  342. if (NULL == pReserved ||
  343. IsBadReadPtr ((const void*)pReserved, (UINT) sizeof (DIHIDFFINITINFO_STRUCT)) )
  344. {
  345. myDebugOut ("CIDirectInputEffectDriver::DeviceID E_INVALIDARG (pReserved is NULL!)\n");
  346. return E_INVALIDARG;
  347. // Call the default guy
  348. //return m_pIPIDEffectDriver->DeviceID(dwDIVersion, dwExternalID, dwIsBegining, dwInternalID, pReserved);
  349. }
  350. //
  351. // get the handle for this device
  352. //
  353. WCHAR* pwcInstanceName = ((DIHIDFFINITINFO_STRUCT*)(pReserved))->pwszDeviceInterface;
  354. DWORD dwBytesReturned;
  355. BOOL fSuccess = ::DeviceIoControl(m_hKernelDeviceDriver, IOCTL_GCK_GET_HANDLE,
  356. pwcInstanceName, ::wcslen(pwcInstanceName)*sizeof(WCHAR),
  357. &m_dwGcKernelDevice, sizeof(m_dwGcKernelDevice), &dwBytesReturned,
  358. NULL);
  359. if (fSuccess != FALSE)
  360. {
  361. // Update the force block
  362. fSuccess =::DeviceIoControl(m_hKernelDeviceDriver, IOCTL_GCK_GET_FF_SCHEME_DATA,
  363. (void*)(&m_dwGcKernelDevice), sizeof(DWORD),
  364. (void*)(&m_ForceMapping), sizeof(m_ForceMapping), &dwBytesReturned,
  365. NULL);
  366. // Get the duplicate handle for the thread
  367. BOOL bDuplicated = ::DuplicateHandle(::GetCurrentProcess(), m_hKernelDeviceDriver, ::GetCurrentProcess(), &m_hKernelDeviceDriverDuplicate, 0, FALSE, DUPLICATE_SAME_ACCESS);
  368. if ((m_hKernelDeviceDriverDuplicate == INVALID_HANDLE_VALUE) || (bDuplicated == FALSE))
  369. {
  370. m_hKernelDeviceDriverDuplicate = NULL;
  371. }
  372. else
  373. {
  374. m_hForceSchemeChangeWaitThread = ::CreateThread(NULL, 0, DoWaitForForceSchemeChange, (void*)this, 0, &m_dwForceSchemeChangeThreadID);
  375. }
  376. }
  377. else
  378. {
  379. myDebugOut ("CIDirectInputEffectDriver::DeviceID IOCTL_GCK_GET_HANDLE Failed!\n");
  380. }
  381. // Close since I need to reopen at the end (why is this happening?)
  382. ::CloseHandle(m_hKernelDeviceDriver);
  383. m_hKernelDeviceDriver = NULL;
  384. }
  385. }
  386. // Hack to get PID.DLL to place keys in registry.
  387. // -- It won't place them if OEM-FF Key is already there
  388. /*
  389. if (bPossiblyFirstTime == true)
  390. {
  391. HKEY hkeyOEM = NULL;
  392. ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("System\\CurrentControlSet\\Control\\MediaProperties\\PrivateProperties\\Joystick\\OEM"), 0, KEY_ALL_ACCESS, &hkeyOEM);
  393. if (hkeyOEM != NULL)
  394. {
  395. // Open key specific to the current device (VIDPID is in m_HidAttributes)
  396. HKEY hkeyOEMForceFeedback = NULL;
  397. TCHAR rgtcDeviceName[64];
  398. ::wsprintf(rgtcDeviceName, TEXT("VID_%04X&PID_%04X\\OEMForceFeedback"), m_HidAttributes.VendorID, m_HidAttributes.ProductID);
  399. ::RegOpenKeyEx(hkeyOEM, rgtcDeviceName, 0, KEY_ALL_ACCESS, &hkeyOEMForceFeedback);
  400. if (hkeyOEMForceFeedback != NULL)
  401. {
  402. // Check to see if the effects key is already there
  403. HKEY hkeyEffects = NULL;
  404. ::RegOpenKeyEx(hkeyOEMForceFeedback, TEXT("Effects"), 0, KEY_READ, &hkeyEffects);
  405. ::RegCloseKey(hkeyOEMForceFeedback);
  406. if (hkeyEffects != NULL)
  407. {
  408. // Effects key is there, this is not the first time we have run
  409. ::RegCloseKey(hkeyEffects);
  410. bPossiblyFirstTime = false;
  411. }
  412. else // Delete the whole OEM ForceFeedback key
  413. {
  414. ::RegDeleteKey(hkeyOEM, rgtcDeviceName);
  415. }
  416. }
  417. }
  418. ::RegCloseKey(hkeyOEM);
  419. }
  420. */
  421. // Call the drivers DeviceID (if we have removed the OEMFF Key it will repopulate)
  422. HRESULT hrPID = m_pIPIDEffectDriver->DeviceID(dwDIVersion, dwExternalID, dwIsBegining, dwInternalID, pReserved);
  423. // Do we need to put ourselves back as the DIEffectDriver?
  424. /* if (bPossiblyFirstTime == true)
  425. {
  426. HKEY hkeyOEM = NULL;
  427. ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("System\\CurrentControlSet\\Control\\MediaProperties\\PrivateProperties\\Joystick\\OEM"), 0, KEY_ALL_ACCESS, &hkeyOEM);
  428. if (hkeyOEM != NULL)
  429. {
  430. HKEY hkeyOEMForceFeedback = NULL;
  431. TCHAR rgtcDeviceName[64];
  432. ::wsprintf(rgtcDeviceName, TEXT("VID_%04X&PID_%04X\\OEMForceFeedback"), m_HidAttributes.VendorID, m_HidAttributes.ProductID);
  433. ::RegOpenKeyEx(hkeyOEM, rgtcDeviceName, 0, KEY_ALL_ACCESS, &hkeyOEMForceFeedback);
  434. // Set the registry CLSID value to us
  435. if (hkeyOEMForceFeedback != NULL)
  436. {
  437. ::RegSetValueEx(hkeyOEMForceFeedback, TEXT("CLSID"), 0, REG_SZ, (BYTE*)CLSID_SWPIDDriver_String, _tcslen(CLSID_SWPIDDriver_String) * sizeof(TCHAR));
  438. ::RegCloseKey(hkeyOEMForceFeedback);
  439. }
  440. ::RegCloseKey(hkeyOEM);
  441. }
  442. }
  443. */
  444. return hrPID; // Value from the System PID driver
  445. }
  446. HRESULT __stdcall CIDirectInputEffectDriver::GetVersions
  447. (
  448. DIDRIVERVERSIONS* pDriverVersions
  449. )
  450. {
  451. myDebugOut ("CIDirectInputEffectDriver::GetVersions (pDriverVersions:0x%08p)\n", pDriverVersions);
  452. return m_pIPIDEffectDriver->GetVersions(pDriverVersions);
  453. }
  454. HRESULT __stdcall CIDirectInputEffectDriver::Escape
  455. (
  456. DWORD dwDeviceID,
  457. DWORD dwEffectID,
  458. DIEFFESCAPE* pEscape
  459. )
  460. {
  461. myDebugOut ("CIDirectInputEffectDriver::Escape (dwDeviceID:0x%08p, dwEffectID:0x%08p, pEscape:0x%08p)\n", dwDeviceID, dwEffectID, pEscape);
  462. return m_pIPIDEffectDriver->Escape(dwDeviceID, dwEffectID, pEscape);
  463. }
  464. /***********************************************************************************
  465. **
  466. ** void CIDirectInputEffectDriver::SetGain(DWORD dwDeviceID, DWORD dwGain)
  467. **
  468. ** @func Modifies the user gain based on settings and sends it down to the lower PID driver
  469. **
  470. ** @rdesc Nothing
  471. **
  472. *************************************************************************************/
  473. HRESULT __stdcall CIDirectInputEffectDriver::SetGain
  474. (
  475. DWORD dwDeviceID, //@parm [IN] ID for device of interest
  476. DWORD dwGain //@parm [IN] User selected gain
  477. )
  478. {
  479. dwGain *= m_ForceMapping.usGain/1000; // 0 - 100K
  480. dwGain /= 10; // 0 - 10K
  481. myDebugOut ("CIDirectInputEffectDriver::SetGain (dwDeviceID:%d, dwGain:%05d:)\n", dwDeviceID, dwGain);
  482. return m_pIPIDEffectDriver->SetGain(dwDeviceID, dwGain);
  483. }
  484. /***********************************************************************************
  485. **
  486. ** HRESULT CopyW2T(LPWSTR pswDest, UINT *puDestSize, LPTSTR ptszSrc)
  487. **
  488. ** @mfunc Copies a WCHAR into a TCHAR while checking buffer length
  489. **
  490. ** @rdesc S_OK on success, MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_INSUFFICIENT_BUFFER)
  491. ** if destination buffer is too small
  492. **
  493. *************************************************************************************/
  494. HRESULT CopyW2T
  495. (
  496. LPTSTR ptszDest, // @parm pointer to WCHAR destination buffer
  497. UINT& ruDestSize, // @parm size of dest in WCHAR's
  498. LPCWSTR pwcszSrc // @parm pointer to NULL terminated source string
  499. )
  500. {
  501. UINT uSizeRequired;
  502. HRESULT hr = S_OK;
  503. uSizeRequired = wcslen(pwcszSrc)+1; //the one is for a NULL character
  504. if(ruDestSize < uSizeRequired)
  505. {
  506. hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_INSUFFICIENT_BUFFER);
  507. }
  508. else
  509. {
  510. //
  511. // we always return wide, but TCHAR can be WCHAR or char
  512. // this compile time so use preprocessor
  513. //
  514. #ifdef UNICODE
  515. wcscpy(ptszDest, pwcszSrc);
  516. #else
  517. int iRetVal=WideCharToMultiByte
  518. (
  519. CP_ACP,
  520. 0,
  521. pwcszSrc,
  522. -1,
  523. ptszDest,
  524. ruDestSize,
  525. NULL,
  526. NULL
  527. );
  528. if(0==iRetVal)
  529. hr=GetLastError();
  530. #endif //UNICODE
  531. }
  532. //Copy size required, or chars copied (same thing)
  533. ruDestSize = uSizeRequired;
  534. return hr;
  535. }
  536. /***********************************************************************************
  537. **
  538. ** void CIDirectInputEffectDriver::InitHidInformation(void* HidInformation)
  539. **
  540. ** @func Open a hid path to the driver, and get preparsed data and hid caps.
  541. **
  542. ** @rdesc Nothing
  543. **
  544. *************************************************************************************/
  545. void CIDirectInputEffectDriver::InitHidInformation
  546. (
  547. LPDIHIDFFINITINFO pHIDInitInfo //@parm [IN] Pointer to structure containing the HID device name
  548. )
  549. {
  550. myDebugOut ("CIDirectInputEffectDriver::InitHidInformation (pHIDInitInfo: 0x%08p)\n", pHIDInitInfo);
  551. if (pHIDInitInfo != NULL)
  552. {
  553. TCHAR ptchHidDeviceName[MAX_PATH];
  554. unsigned int dwSize = MAX_PATH;
  555. ::CopyW2T(ptchHidDeviceName, dwSize, pHIDInitInfo->pwszDeviceInterface);
  556. m_hHidDeviceDriver = ::CreateFile(ptchHidDeviceName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_DELETE_ON_CLOSE, NULL);
  557. if (m_hHidDeviceDriver == INVALID_HANDLE_VALUE)
  558. {
  559. m_hHidDeviceDriver = NULL;
  560. return;
  561. }
  562. if (m_pPreparsedData == NULL)
  563. {
  564. ::HidD_GetPreparsedData(m_hHidDeviceDriver, &m_pPreparsedData);
  565. if (m_pPreparsedData == NULL)
  566. {
  567. return;
  568. }
  569. }
  570. ::HidP_GetCaps(m_pPreparsedData, &m_HidCaps);
  571. // Find VID/PID the USB way!
  572. ::HidD_GetAttributes(m_hHidDeviceDriver, &m_HidAttributes);
  573. }
  574. }
  575. /***********************************************************************************
  576. **
  577. ** void CIDirectInputEffectDriver::SendSpringChange()
  578. **
  579. ** @func Sends a new Spring Modify report to the driver
  580. **
  581. ** @rdesc Nothing
  582. **
  583. *************************************************************************************/
  584. void CIDirectInputEffectDriver::SendSpringChange()
  585. {
  586. myDebugOut ("CIDirectInputEffectDriver::SendSpringChange ()\n");
  587. if ((m_hHidDeviceDriver != NULL) && (m_pPreparsedData != NULL))
  588. {
  589. // Setup the spring report
  590. // 1. Allocate an array of max output size
  591. BYTE* pbOutReport = new BYTE[m_HidCaps.OutputReportByteLength];
  592. if (pbOutReport == NULL)
  593. {
  594. return;
  595. }
  596. // 2. Zero out array
  597. ::memset(pbOutReport, 0, m_HidCaps.OutputReportByteLength);
  598. // 3. Set the proper report ID
  599. pbOutReport[0] = c_bSideWinderPIDReportID_SetEffect;
  600. // 4. Cheat since we know what the firmware is expecting (Use usage Gunk where easy)
  601. pbOutReport[1] = c_EffectID_RTCSpring; // Effect Block Index (ID)
  602. unsigned short usRTC = m_ForceMapping.usRTC; // 0 - 10K
  603. usRTC /= 100; // 0 - 100
  604. usRTC *= 255; // 0 - 25500
  605. usRTC /= 100; // 0 - 255
  606. if (usRTC > 255)
  607. {
  608. usRTC = 255;
  609. }
  610. pbOutReport[9] = BYTE(usRTC); // Effect Gain - Only item the RTC Spring will look at
  611. myDebugOut ("CIDirectInputEffectDriver::SendSpringChange -> usRTC:%03d\n", usRTC);
  612. // 5. Send the report down
  613. DWORD dwBytesWritten;
  614. ::WriteFile(m_hHidDeviceDriver, pbOutReport, m_HidCaps.OutputReportByteLength, &dwBytesWritten, NULL);
  615. // 6. Deallocate report array
  616. delete[] pbOutReport;
  617. }
  618. }
  619. /***********************************************************************************
  620. **
  621. ** void CIDirectInputEffectDriver::SendForceFeedbackCommand()
  622. **
  623. ** @func Intercepting this call gives us the chance to set the force level of the
  624. ** RTC Spring after a reset
  625. **
  626. ** @rdesc Result of SendForceFeedbackCommand (from lower driver)
  627. **
  628. *************************************************************************************/
  629. HRESULT __stdcall CIDirectInputEffectDriver::SendForceFeedbackCommand
  630. (
  631. DWORD dwDeviceID, //@parm [IN] ID of device this is for
  632. DWORD dwState //@parm [IN] The command (we are interested in reset)
  633. )
  634. {
  635. myDebugOut ("CIDirectInputEffectDriver::SendForceFeedbackCommand Enter (dwDeviceID:%x, dwState:0x%08p)\n", dwDeviceID, dwState);
  636. HRESULT hr = m_pIPIDEffectDriver->SendForceFeedbackCommand(dwDeviceID, dwState);
  637. myDebugOut ("CIDirectInputEffectDriver::SendForceFeedbackCommand Calling Base (hr:0x%08p)\n", hr);
  638. if (dwState == DISFFC_RESET) // This is how they turn on the RTC Spring
  639. {
  640. myDebugOut ("CIDirectInputEffectDriver::SendForceFeedbackCommand RESET sent!\n");
  641. SendSpringChange();
  642. }
  643. return hr;
  644. }
  645. HRESULT __stdcall CIDirectInputEffectDriver::GetForceFeedbackState
  646. (
  647. DWORD dwDeviceID,
  648. DIDEVICESTATE* pDeviceState
  649. )
  650. {
  651. myDebugOut ("CIDirectInputEffectDriver::GetForceFeedbackState Begin (dwDeviceID:%d, pDeviceState:0x%08p)\n", dwDeviceID, pDeviceState);
  652. HRESULT hrPidDriver = S_OK;
  653. __try
  654. {
  655. hrPidDriver = m_pIPIDEffectDriver->GetForceFeedbackState(dwDeviceID, pDeviceState);
  656. }
  657. __except ((GetExceptionCode() == EXCEPTION_INT_DIVIDE_BY_ZERO) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
  658. {
  659. hrPidDriver = DIERR_INPUTLOST;
  660. _RPT0(_CRT_WARN, "!!! Caught EXCEPTION_INT_DIVIDE_BY_ZERO !!!\n");
  661. }
  662. myDebugOut ("CIDirectInputEffectDriver::GetForceFeedbackState End (dwDeviceID:%d, pDeviceState:0x%08p; hr: 0x%08x)\n",
  663. dwDeviceID, pDeviceState, hrPidDriver);
  664. return hrPidDriver;
  665. }
  666. /***********************************************************************************
  667. **
  668. ** void PercentagesFromAngle()
  669. **
  670. ** @func Extrapolate the percentages from the table. Makes use of the fact that
  671. ** sin^2(angle) + cos^2(angle) = 1 and xPercentage + yPercentage = 1
  672. **
  673. ** @rdesc Result of download (from lower driver)
  674. **
  675. *************************************************************************************/
  676. void PercentagesFromAngle
  677. (
  678. DWORD dwAngle, //@parm [IN] Angle to convert to percentages
  679. LONG& lXPercent, //@parm [OUT] Resultant X Percentage
  680. LONG& lYPercent //@parm [OUT] Resultant Y Percentage
  681. )
  682. {
  683. // Get the angle mapping into the first quadrant
  684. DWORD dwMappingAngle = dwAngle; // 0 - 9000
  685. bool bFlipSignX = false; // X is negative in 3rd and 4th quadrants
  686. bool bFlipSignY = true; // Y is negative in 1st and 4th quadrants
  687. if (dwAngle > 9000)
  688. {
  689. bFlipSignY = false;
  690. if (dwAngle > 18000)
  691. {
  692. bFlipSignX = true;
  693. if (dwAngle > 27000) // 27000 - 36000
  694. {
  695. bFlipSignY = true;
  696. dwMappingAngle = 36000 - dwAngle;
  697. }
  698. else // 18000 - 27000
  699. {
  700. dwMappingAngle = dwAngle - 18000;
  701. }
  702. }
  703. else // 9000 - 18000
  704. {
  705. dwMappingAngle = 18000 - dwAngle;
  706. }
  707. }
  708. _ASSERTE(dwMappingAngle <= 9000);
  709. DWORD quantizedEntry = dwMappingAngle / c_dwTableQuantization;
  710. DWORD quantizedAngle = quantizedEntry * c_dwTableQuantization;
  711. if (dwMappingAngle == quantizedAngle)
  712. {
  713. lXPercent = g_PercentagesArray[quantizedEntry].dwPercentageX;
  714. }
  715. else
  716. {
  717. _ASSERTE(quantizedAngle < dwMappingAngle);
  718. _ASSERTE(dwMappingAngle < 9000);
  719. DWORD lValue = g_PercentagesArray[quantizedEntry].dwPercentageX;
  720. DWORD rValue = g_PercentagesArray[quantizedEntry + 1].dwPercentageX;
  721. long int lSlope = ((rValue - lValue) * 1000)/c_dwTableQuantization;
  722. lXPercent = lValue + lSlope * (dwMappingAngle - quantizedAngle);
  723. }
  724. lYPercent = 10000 - lXPercent;
  725. if (bFlipSignX == true)
  726. {
  727. lXPercent *= -1;
  728. }
  729. if (bFlipSignY == true)
  730. {
  731. lYPercent *= -1;
  732. }
  733. }
  734. /***********************************************************************************
  735. **
  736. ** void CIDirectInputEffectDriver::DownloadEffect()
  737. **
  738. ** @func Intercepting this call gives us the chance to map the Y forces to the X
  739. ** axis. Switches off the type to determine if the mapping is done.
  740. **
  741. ** @rdesc Result of download (from lower driver)
  742. **
  743. *************************************************************************************/
  744. HRESULT __stdcall CIDirectInputEffectDriver::DownloadEffect
  745. (
  746. DWORD dwDeviceID, //@parm [IN] ID of device this is for
  747. DWORD dwInternalEffectType, //@parm [IN] Type of effect (major, minor)
  748. DWORD* pdwDnloadID, //@parm [IN, OUT] >0 - ID of effect to modify. 0 new effect ID returned
  749. DIEFFECT* pEffect, //@parm [IN, OUT] Structure containing effect information
  750. DWORD dwFlags //@parm [IN] Download flags
  751. )
  752. {
  753. /* LogIt("CIDirectInputEffectDriver::DownloadEffect:\n");
  754. LogIt("\tdwInternalEffectType: 0x%08X\n", dwInternalEffectType);
  755. LogIt("\tpdwDnloadID: 0x%08X", pdwDnloadID);
  756. if (pdwDnloadID != NULL)
  757. {
  758. LogIt(" (0x%08X)", *pdwDnloadID);
  759. }
  760. LogIt("\n\tpEffect: 0x%08X\n", pEffect);
  761. if (pEffect != NULL)
  762. {
  763. LogIt("\t\trglDirection[0]: %ld\n", pEffect->rglDirection[0]);
  764. LogIt("\t\tdwFlags: 0x%08X\n", pEffect->dwFlags);
  765. LogIt("\t\tdwGain: 0x%08X\n", pEffect->dwGain);
  766. }
  767. LogIt("\tdwFlags: 0x%08X\n", dwFlags);
  768. */
  769. DWORD dwOriginalEffectGain = pEffect->dwGain;
  770. myDebugOut ("CIDirectInputEffectDriver::DownloadEffect (<NOT DEBUGGED>)\n");
  771. if (pEffect == NULL)
  772. {
  773. return E_INVALIDARG;
  774. }
  775. WORD wType = WORD(dwInternalEffectType & 0x0000FFFF);
  776. bool bGainTruncation = false;
  777. // case EF_BEHAVIOR: // We don't axis-map behaviour
  778. // case EF_USER_DEFINED: // We don't axis-map user defined
  779. // case EF_RTC_SPRING: // We don't axis-map RTC spring
  780. // case EF_VFX_EFFECT: // Visual force VFX Effect!!! Danger Will Robinson!
  781. if ((m_ForceMapping.bMapYToX) && ((wType >= PID_CONSTANT_FORCE) && (wType <= PID_SAWTOOTHDOWN)))
  782. {
  783. // We don't support more than 2 axes (currently), and 0 is probably an error
  784. if ((pEffect->cAxes > 2) || (pEffect->cAxes == 0))
  785. {
  786. return E_NOTIMPL;
  787. }
  788. // We don't support sperical (3 axis force)
  789. if (pEffect->dwFlags & DIEFF_SPHERICAL)
  790. {
  791. return E_NOTIMPL; // .. since got by axis check, programmer goofed up anyway
  792. }
  793. // Are the axes reversed?
  794. bool bAxesReversed = (DIDFT_GETINSTANCE(pEffect->rgdwAxes[0]) == 1);
  795. LONG lPercentX = 0;
  796. LONG lPercentY = 0;
  797. // Polar, figure out percentage that is X and percentage that is Y
  798. if (pEffect->dwFlags & DIEFF_POLAR)
  799. {
  800. if (pEffect->cAxes == 1) // Polar coordinate must have two axes of data (because DX says so)
  801. {
  802. _RPT0(_CRT_WARN, "POLAR effect that has only one AXIS\n");
  803. // return E_INVALIDARG;
  804. }
  805. long int lEffectAngle = pEffect->rglDirection[0]; // in [0] even if reversed
  806. if (bAxesReversed == true) { // Indicates (-1, 0) as origin instead of (0, -1)
  807. lEffectAngle += 27000;
  808. }
  809. while (lEffectAngle < 0) // Make it positive
  810. {
  811. lEffectAngle += 36000;
  812. }
  813. lEffectAngle %= 36000; // Make it from 0 to 35900
  814. PercentagesFromAngle(DWORD(lEffectAngle), lPercentX, lPercentY);
  815. // Not going to bother reseting the angle, since PID.dll just sends it down and wheel ignores Y component
  816. }
  817. else if (pEffect->dwFlags & DIEFF_CARTESIAN)
  818. {
  819. // Here I remove the Y component in case PID.dll maps this to an angle.
  820. if (bAxesReversed == true)
  821. {
  822. lPercentX = pEffect->rglDirection[1];
  823. lPercentY = pEffect->rglDirection[0];
  824. pEffect->rglDirection[0] = 0;
  825. }
  826. else
  827. {
  828. lPercentX = pEffect->rglDirection[0];
  829. lPercentY = pEffect->rglDirection[1];
  830. pEffect->rglDirection[1] = 0;
  831. }
  832. LONG lTotal = abs(lPercentX) + abs(lPercentY);
  833. // DIV ZERO Bug
  834. // If both of the percentages are zero then do nothing
  835. // Jen-Hung Ho
  836. if (lTotal)
  837. {
  838. lPercentX = (lPercentX * 10000)/lTotal;
  839. if ( lPercentY > 0 )
  840. lPercentY = 10000 - abs(lPercentX);
  841. else
  842. lPercentY = abs(lPercentX) - 10000;
  843. }
  844. }
  845. else
  846. {
  847. _ASSERTE(FALSE);
  848. return E_NOTIMPL; // Some new fangled coordinate system
  849. }
  850. #if 0 // tempory remove by Jen-Hung Ho
  851. long int lContributionY = lPercentY/c_lContributionY;
  852. long int lTotal = lPercentX + lContributionY;
  853. #else
  854. long int lTotal;
  855. long int lContributionY = lPercentY/c_lContributionY;
  856. #endif
  857. // If POLAR set proper angle
  858. if (pEffect->dwFlags & DIEFF_POLAR)
  859. {
  860. // Keep as orginal code, add by Jen-Hung Ho
  861. lTotal = lPercentX + lContributionY;
  862. if (lTotal < 0)
  863. {
  864. pEffect->rglDirection[0] = (bAxesReversed == true) ? 0 : 27000;
  865. }
  866. else
  867. {
  868. pEffect->rglDirection[0] = (bAxesReversed == true) ? 18000 : 9000;
  869. }
  870. }
  871. else // Cartesian
  872. {
  873. // use X axis force to determain direction, add by Jen-Hung Ho
  874. // Y axis force follow X axis direction
  875. if ( lPercentX > 0 )
  876. lTotal = lPercentX + abs(lContributionY);
  877. else if ( lPercentX < 0 )
  878. lTotal = lPercentX - abs(lContributionY);
  879. else
  880. lTotal = lContributionY;
  881. // Already removed Y above
  882. if (bAxesReversed == true)
  883. {
  884. pEffect->rglDirection[1] = lTotal;
  885. }
  886. else
  887. {
  888. pEffect->rglDirection[0] = lTotal;
  889. }
  890. }
  891. // Allmost all the time we are changing the angle (and pid always sends it anyways)
  892. dwFlags |= DIEP_DIRECTION;
  893. // We avoid causing truncation - what if there was truncation? Need to check and return
  894. if (pEffect->dwGain > 10000)
  895. {
  896. bGainTruncation = true;
  897. }
  898. if (pEffect->dwFlags & DIEFF_POLAR)
  899. {
  900. // Modify the gain based on lPercentX and lPercentY
  901. pEffect->dwGain = pEffect->dwGain * abs(lTotal);
  902. pEffect->dwGain /= 10000; // Put back in range 0 - 10000
  903. }
  904. // Make sure we don't go out of range and cause DI_TRUNCATED to be returned from below
  905. if (pEffect->dwGain > 10000)
  906. {
  907. pEffect->dwGain = 10000;
  908. }
  909. }
  910. else // We are not mapping fix cartesian pid bug
  911. {
  912. // Cartesian
  913. if (pEffect->dwFlags & DIEFF_CARTESIAN)
  914. {
  915. short int xAxisIndex = 0;
  916. short int yAxisIndex = 1;
  917. // Are the axes reversed?
  918. if (DIDFT_GETINSTANCE(pEffect->rgdwAxes[0]) == 1)
  919. {
  920. xAxisIndex = 1;
  921. yAxisIndex = 0;
  922. }
  923. LONG lTotal = abs(pEffect->rglDirection[0]) + abs(pEffect->rglDirection[1]);
  924. // Fixup the X component so the total maginitude is base on 10K
  925. if (lTotal)
  926. {
  927. pEffect->rglDirection[xAxisIndex] = (10000 * pEffect->rglDirection[xAxisIndex])/lTotal;
  928. }
  929. // Remove the Y component to keep PID.dll from playing with it.
  930. pEffect->rglDirection[yAxisIndex] = 0;
  931. }
  932. }
  933. HRESULT hr = m_pIPIDEffectDriver->DownloadEffect(dwDeviceID, dwInternalEffectType, pdwDnloadID, pEffect, dwFlags);
  934. pEffect->dwGain = dwOriginalEffectGain;
  935. if ((hr == S_OK) && (bGainTruncation == true))
  936. {
  937. hr = DI_TRUNCATED;
  938. }
  939. /* LogIt("-- pdwDnloadID: 0x%08X", pdwDnloadID);
  940. if (pdwDnloadID != NULL)
  941. {
  942. LogIt(" (0x%08X)", *pdwDnloadID);
  943. }
  944. LogIt("--\n", hr);
  945. */ return hr;
  946. }
  947. HRESULT __stdcall CIDirectInputEffectDriver::DestroyEffect
  948. (
  949. DWORD dwDeviceID,
  950. DWORD dwDnloadID
  951. )
  952. {
  953. myDebugOut ("CIDirectInputEffectDriver::DestroyEffect Enter(dwDeviceID:%d, dwDnloadID:%d)\n",
  954. dwDeviceID, dwDnloadID);
  955. HRESULT hr = m_pIPIDEffectDriver->DestroyEffect(dwDeviceID, dwDnloadID);
  956. myDebugOut ("CIDirectInputEffectDriver::DestroyEffect Exit (hr:0x%08p)\n", hr);
  957. return hr;
  958. }
  959. HRESULT __stdcall CIDirectInputEffectDriver::StartEffect
  960. (
  961. DWORD dwDeviceID,
  962. DWORD dwDnloadID,
  963. DWORD dwMode,
  964. DWORD dwIterations
  965. )
  966. {
  967. myDebugOut ("CIDirectInputEffectDriver::StartEffect (<NOT DEBUGGED>)\n");
  968. return m_pIPIDEffectDriver->StartEffect(dwDeviceID, dwDnloadID, dwMode, dwIterations);
  969. }
  970. HRESULT __stdcall CIDirectInputEffectDriver::StopEffect
  971. (
  972. DWORD dwDeviceID,
  973. DWORD dwDnloadID
  974. )
  975. {
  976. myDebugOut ("CIDirectInputEffectDriver::StopEffect (<NOT DEBUGGED>)\n");
  977. return m_pIPIDEffectDriver->StopEffect(dwDeviceID, dwDnloadID);
  978. }
  979. HRESULT __stdcall CIDirectInputEffectDriver::GetEffectStatus
  980. (
  981. DWORD dwDeviceID,
  982. DWORD dwDnloadID,
  983. DWORD* pdwStatusCode
  984. )
  985. {
  986. myDebugOut ("CIDirectInputEffectDriver::GetEffectStatus (<NOT DEBUGGED>)\n");
  987. return m_pIPIDEffectDriver->GetEffectStatus(dwDeviceID, dwDnloadID, pdwStatusCode);
  988. }
  989. DWORD __stdcall DoWaitForForceSchemeChange(void* pParameter)
  990. {
  991. myDebugOut ("CIDirectInputEffectDriver DoWaitForForceSchemeChange (pParameter: 0x%08p)\n", pParameter);
  992. CIDirectInputEffectDriver* pIDirectInputEffectDriver = (CIDirectInputEffectDriver*)pParameter;
  993. //TODO remove this it could be really slow!
  994. if (IsBadReadPtr ((const void*)pParameter, sizeof CIDirectInputEffectDriver))
  995. {
  996. myDebugOut ("CIDirectInputEffectDriver DoWaitForForceSchemeChange pParameter is not a valid read ptr!\n");
  997. }
  998. if (pIDirectInputEffectDriver != NULL)
  999. {
  1000. pIDirectInputEffectDriver->WaitForForceSchemeChange();
  1001. }
  1002. return 0;
  1003. }
  1004. /***********************************************************************************
  1005. **
  1006. ** void CIDirectInputEffectDriver::WaitForForceSchemeChange()
  1007. **
  1008. ** @func Thread waits on the Event signal for force scheme change until the object goes away.
  1009. ** If event is signaled, WaitForForceSchemeChange() is called
  1010. **
  1011. ** @rdesc Nothing
  1012. **
  1013. *************************************************************************************/
  1014. void CIDirectInputEffectDriver::WaitForForceSchemeChange()
  1015. {
  1016. _ASSERTE(m_hKernelDeviceDriverDuplicate != NULL);
  1017. if (IsBadReadPtr ((const void*)this, sizeof CIDirectInputEffectDriver))
  1018. {
  1019. myDebugOut ("CIDirectInputEffectDriver WaitForForceSchemeChange is not a valid read ptr!\n");
  1020. }
  1021. FORCE_BLOCK forceMap;
  1022. DWORD dwReturnDataSize = 0;
  1023. for (;m_ulReferenceCount != 0;)
  1024. {
  1025. // Set up the IOCTL
  1026. BOOL bRet = ::DeviceIoControl(m_hKernelDeviceDriverDuplicate, IOCTL_GCK_NOTIFY_FF_SCHEME_CHANGE,
  1027. (void*)(&m_dwGcKernelDevice), sizeof(DWORD), // In
  1028. (void*)(&forceMap), sizeof(forceMap), &dwReturnDataSize, // Out
  1029. NULL);
  1030. _RPT0(_CRT_WARN, "Returned from Scheme Change!\n");
  1031. if ((m_ulReferenceCount != 0) && (bRet != FALSE) && (dwReturnDataSize == sizeof(forceMap)))
  1032. {
  1033. // Need a mutext here
  1034. m_ForceMapping = forceMap;
  1035. SendSpringChange();
  1036. SetGain(m_dwInternalDeviceID, 10000);
  1037. }
  1038. else
  1039. { // We are done
  1040. ::CloseHandle(m_hKernelDeviceDriverDuplicate);
  1041. m_hKernelDeviceDriverDuplicate = NULL;
  1042. ExitThread(2);
  1043. }
  1044. }
  1045. }