Counter Strike : Global Offensive Source Code
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.

833 lines
20 KiB

  1. //====== Copyright � 1996-2004, Valve Corporation, All rights reserved. =======
  2. //
  3. // Purpose: Force feeback OS level handlers
  4. //
  5. //=============================================================================
  6. #include <windows.h>
  7. #include "basehandle.h"
  8. #include "UtlVector.h"
  9. #include "usercmd.h"
  10. #include "cdll_client_int.h"
  11. #include "cdll_util.h"
  12. #include "input.h"
  13. #include "convar.h"
  14. #include "tier0/icommandline.h"
  15. #include "forcefeedback.h"
  16. #include "FileSystem.h"
  17. #define DIRECTINPUT_VERSION 0x0800
  18. #include "dinput.h"
  19. // memdbgon must be the last include file in a .cpp file!!!
  20. #include "tier0/memdbgon.h"
  21. static ConVar ff_autocenter( "ff_autocenter", "1", FCVAR_ARCHIVE, "Enable auto-centering of forcefeedback joystick." );
  22. struct ForceFeedbackParams_t
  23. {
  24. bool m_bForceFeedbackAvailable;
  25. LPDIRECTINPUT8 m_pIInput;
  26. LPDIRECTINPUTDEVICE8 m_pIJoystick;
  27. bool m_bPaused;
  28. };
  29. typedef CUtlVector< LPDIRECTINPUTEFFECT > vecEffectPtr_t;
  30. class EffectMap_t
  31. {
  32. public:
  33. FORCEFEEDBACK_t effect;
  34. char const *effectfile;
  35. vecEffectPtr_t *pVecEffectPtr;
  36. bool m_bDownloaded;
  37. };
  38. static EffectMap_t g_EffectMap[] =
  39. {
  40. { FORCE_FEEDBACK_SHOT_SINGLE, "scripts/forcefeedback/singleshot.ffe" },
  41. { FORCE_FEEDBACK_SHOT_DOUBLE, "scripts/forcefeedback/doubleshot.ffe" },
  42. { FORCE_FEEDBACK_TAKEDAMAGE, "scripts/forcefeedback/takedamage.ffe" },
  43. { FORCE_FEEDBACK_SCREENSHAKE, "scripts/forcefeedback/screenshake.ffe" },
  44. { FORCE_FEEDBACK_SKIDDING, "scripts/forcefeedback/skidding.ffe" },
  45. { FORCE_FEEDBACK_BREAKING, "scripts/forcefeedback/breaking.ffe" },
  46. };
  47. static void InitEffectMap()
  48. {
  49. int c = ARRAYSIZE( g_EffectMap );
  50. for ( int i = 0; i < c; ++i )
  51. {
  52. g_EffectMap[ i ].pVecEffectPtr = new vecEffectPtr_t();
  53. }
  54. }
  55. static void ShutdownEffectMap()
  56. {
  57. int c = ARRAYSIZE( g_EffectMap );
  58. for ( int i = 0; i < c; ++i )
  59. {
  60. if ( g_EffectMap[ i ].pVecEffectPtr )
  61. {
  62. g_EffectMap[ i ].pVecEffectPtr->RemoveAll();
  63. delete g_EffectMap[ i ].pVecEffectPtr;
  64. }
  65. g_EffectMap[ i ].pVecEffectPtr = NULL;
  66. }
  67. }
  68. static void ReportCap( int flags, int bits, char const *desc )
  69. {
  70. if ( flags & bits )
  71. {
  72. DevMsg( "%s\n", desc );
  73. }
  74. }
  75. static void ReportDevType( DWORD devType )
  76. {
  77. byte baseType = GET_DIDEVICE_TYPE( devType );
  78. byte subType = GET_DIDEVICE_SUBTYPE( devType );
  79. switch ( baseType )
  80. {
  81. default:
  82. DevMsg( "unknown type\n" );
  83. break;
  84. case DI8DEVTYPE_DEVICE:
  85. DevMsg( "DEVICE\n" );
  86. break;
  87. case DI8DEVTYPE_MOUSE:
  88. DevMsg( "MOUSE\n" );
  89. switch ( subType )
  90. {
  91. default:
  92. break;
  93. case DI8DEVTYPEMOUSE_UNKNOWN:
  94. DevMsg( "DI8DEVTYPEMOUSE_UNKNOWN\n" );
  95. break;
  96. case DI8DEVTYPEMOUSE_TRADITIONAL:
  97. DevMsg( "DI8DEVTYPEMOUSE_TRADITIONAL\n" );
  98. break;
  99. case DI8DEVTYPEMOUSE_FINGERSTICK:
  100. DevMsg( "DI8DEVTYPEMOUSE_FINGERSTICK\n" );
  101. break;
  102. case DI8DEVTYPEMOUSE_TOUCHPAD:
  103. DevMsg( "DI8DEVTYPEMOUSE_TOUCHPAD\n" );
  104. break;
  105. case DI8DEVTYPEMOUSE_TRACKBALL:
  106. DevMsg( "DI8DEVTYPEMOUSE_TRACKBALL\n" );
  107. break;
  108. case DI8DEVTYPEMOUSE_ABSOLUTE:
  109. DevMsg( "DI8DEVTYPEMOUSE_ABSOLUTE\n" );
  110. break;
  111. }
  112. break;
  113. case DI8DEVTYPE_KEYBOARD:
  114. DevMsg( "KEYBOARD\n" );
  115. switch ( subType )
  116. {
  117. default:
  118. break;
  119. case DI8DEVTYPEKEYBOARD_UNKNOWN:
  120. DevMsg( "DI8DEVTYPEKEYBOARD_UNKNOWN\n" );
  121. break;
  122. case DI8DEVTYPEKEYBOARD_PCXT:
  123. DevMsg( "DI8DEVTYPEKEYBOARD_PCXT\n" );
  124. break;
  125. case DI8DEVTYPEKEYBOARD_OLIVETTI:
  126. DevMsg( "DI8DEVTYPEKEYBOARD_OLIVETTI\n" );
  127. break;
  128. case DI8DEVTYPEKEYBOARD_PCAT:
  129. DevMsg( "DI8DEVTYPEKEYBOARD_PCAT\n" );
  130. break;
  131. case DI8DEVTYPEKEYBOARD_PCENH:
  132. DevMsg( "DI8DEVTYPEKEYBOARD_PCENH:\n" );
  133. break;
  134. case DI8DEVTYPEKEYBOARD_NOKIA1050:
  135. DevMsg( "DI8DEVTYPEKEYBOARD_NOKIA1050\n" );
  136. break;
  137. case DI8DEVTYPEKEYBOARD_NOKIA9140:
  138. DevMsg( "DI8DEVTYPEKEYBOARD_NOKIA9140\n" );
  139. break;
  140. case DI8DEVTYPEKEYBOARD_NEC98:
  141. DevMsg( "DI8DEVTYPEKEYBOARD_NEC98\n" );
  142. break;
  143. case DI8DEVTYPEKEYBOARD_NEC98LAPTOP:
  144. DevMsg( "DI8DEVTYPEKEYBOARD_NEC98LAPTOP\n" );
  145. break;
  146. case DI8DEVTYPEKEYBOARD_NEC98106:
  147. DevMsg( "DI8DEVTYPEKEYBOARD_NEC98106\n" );
  148. break;
  149. case DI8DEVTYPEKEYBOARD_JAPAN106:
  150. DevMsg( "DI8DEVTYPEKEYBOARD_JAPAN106\n" );
  151. break;
  152. case DI8DEVTYPEKEYBOARD_JAPANAX:
  153. DevMsg( "DI8DEVTYPEKEYBOARD_JAPANAX\n" );
  154. break;
  155. case DI8DEVTYPEKEYBOARD_J3100:
  156. DevMsg( "DI8DEVTYPEKEYBOARD_J3100\n" );
  157. break;
  158. }
  159. break;
  160. case DI8DEVTYPE_JOYSTICK:
  161. DevMsg( "JOYSTICK\n" );
  162. switch ( subType )
  163. {
  164. default:
  165. break;
  166. case DI8DEVTYPEJOYSTICK_LIMITED :
  167. DevMsg( "DI8DEVTYPEJOYSTICK_LIMITED\n" );
  168. break;
  169. case DI8DEVTYPEJOYSTICK_STANDARD:
  170. DevMsg( "DI8DEVTYPEJOYSTICK_STANDARD\n" );
  171. break;
  172. }
  173. break;
  174. case DI8DEVTYPE_GAMEPAD:
  175. DevMsg( "GAMEPAD\n" );
  176. switch ( subType )
  177. {
  178. default:
  179. break;
  180. case DI8DEVTYPEGAMEPAD_LIMITED:
  181. DevMsg( "DI8DEVTYPEGAMEPAD_LIMITED\n" );
  182. break;
  183. case DI8DEVTYPEGAMEPAD_STANDARD:
  184. DevMsg( "DI8DEVTYPEGAMEPAD_STANDARD\n" );
  185. break;
  186. case DI8DEVTYPEGAMEPAD_TILT:
  187. DevMsg( "DI8DEVTYPEGAMEPAD_TILT\n" );
  188. break;
  189. }
  190. break;
  191. case DI8DEVTYPE_DRIVING:
  192. DevMsg( "DRIVING\n" );
  193. switch ( subType )
  194. {
  195. default:
  196. break;
  197. case DI8DEVTYPEDRIVING_LIMITED:
  198. DevMsg( "DI8DEVTYPEDRIVING_LIMITED\n" );
  199. break;
  200. case DI8DEVTYPEDRIVING_COMBINEDPEDALS:
  201. DevMsg( "DI8DEVTYPEDRIVING_COMBINEDPEDALS\n" );
  202. break;
  203. case DI8DEVTYPEDRIVING_DUALPEDALS:
  204. DevMsg( "DI8DEVTYPEDRIVING_DUALPEDALS\n" );
  205. break;
  206. case DI8DEVTYPEDRIVING_THREEPEDALS:
  207. DevMsg( "DI8DEVTYPEDRIVING_THREEPEDALS\n" );
  208. break;
  209. case DI8DEVTYPEDRIVING_HANDHELD:
  210. DevMsg( "DI8DEVTYPEDRIVING_HANDHELD\n" );
  211. break;
  212. }
  213. break;
  214. case DI8DEVTYPE_FLIGHT:
  215. DevMsg( "FLIGHT\n" );
  216. switch ( subType )
  217. {
  218. default:
  219. break;
  220. case DI8DEVTYPEFLIGHT_LIMITED:
  221. DevMsg( "DI8DEVTYPEFLIGHT_LIMITED\n" );
  222. break;
  223. case DI8DEVTYPEFLIGHT_STICK:
  224. DevMsg( "DI8DEVTYPEFLIGHT_STICK\n" );
  225. break;
  226. case DI8DEVTYPEFLIGHT_YOKE:
  227. DevMsg( "DI8DEVTYPEFLIGHT_YOKE\n" );
  228. break;
  229. case DI8DEVTYPEFLIGHT_RC:
  230. DevMsg( "DI8DEVTYPEFLIGHT_RC\n" );
  231. break;
  232. }
  233. break;
  234. case DI8DEVTYPE_1STPERSON:
  235. DevMsg( "1STPERSON\n" );
  236. switch ( subType )
  237. {
  238. default:
  239. break;
  240. case DI8DEVTYPE1STPERSON_LIMITED:
  241. DevMsg( "DI8DEVTYPE1STPERSON_LIMITED\n" );
  242. break;
  243. case DI8DEVTYPE1STPERSON_UNKNOWN:
  244. DevMsg( "DI8DEVTYPE1STPERSON_UNKNOWN\n" );
  245. break;
  246. case DI8DEVTYPE1STPERSON_SIXDOF:
  247. DevMsg( "DI8DEVTYPE1STPERSON_SIXDOF\n" );
  248. break;
  249. case DI8DEVTYPE1STPERSON_SHOOTER:
  250. DevMsg( "DI8DEVTYPE1STPERSON_SHOOTER\n" );
  251. break;
  252. }
  253. break;
  254. case DI8DEVTYPE_DEVICECTRL:
  255. DevMsg( "DEVICECTRL\n" );
  256. switch ( subType )
  257. {
  258. default:
  259. break;
  260. case DI8DEVTYPEDEVICECTRL_UNKNOWN:
  261. DevMsg( "DI8DEVTYPEDEVICECTRL_UNKNOWN\n" );
  262. break;
  263. case DI8DEVTYPEDEVICECTRL_COMMSSELECTION:
  264. DevMsg( "DI8DEVTYPEDEVICECTRL_COMMSSELECTION\n" );
  265. break;
  266. case DI8DEVTYPEDEVICECTRL_COMMSSELECTION_HARDWIRED:
  267. DevMsg( "DI8DEVTYPEDEVICECTRL_COMMSSELECTION_HARDWIRED\n" );
  268. break;
  269. }
  270. break;
  271. case DI8DEVTYPE_SCREENPOINTER:
  272. DevMsg( "SCREENPOINTER\n" );
  273. switch ( subType )
  274. {
  275. default:
  276. break;
  277. case DI8DEVTYPESCREENPTR_UNKNOWN:
  278. DevMsg( "DI8DEVTYPESCREENPTR_UNKNOWN\n" );
  279. break;
  280. case DI8DEVTYPESCREENPTR_LIGHTGUN:
  281. DevMsg( "DI8DEVTYPESCREENPTR_LIGHTGUN\n" );
  282. break;
  283. case DI8DEVTYPESCREENPTR_LIGHTPEN:
  284. DevMsg( "DI8DEVTYPESCREENPTR_LIGHTPEN\n" );
  285. break;
  286. case DI8DEVTYPESCREENPTR_TOUCH:
  287. DevMsg( "DI8DEVTYPESCREENPTR_TOUCH\n" );
  288. break;
  289. }
  290. break;
  291. case DI8DEVTYPE_REMOTE:
  292. DevMsg( "REMOTE\n" );
  293. switch ( subType )
  294. {
  295. default:
  296. break;
  297. case DI8DEVTYPEREMOTE_UNKNOWN:
  298. DevMsg( "DI8DEVTYPEREMOTE_UNKNOWN\n" );
  299. break;
  300. }
  301. break;
  302. case DI8DEVTYPE_SUPPLEMENTAL:
  303. DevMsg( "SUPPLEMENTAL\n" );
  304. switch ( subType )
  305. {
  306. default:
  307. break;
  308. case DI8DEVTYPESUPPLEMENTAL_UNKNOWN:
  309. DevMsg( "DI8DEVTYPESUPPLEMENTAL_UNKNOWN\n" );
  310. break;
  311. case DI8DEVTYPESUPPLEMENTAL_2NDHANDCONTROLLER:
  312. DevMsg( "DI8DEVTYPESUPPLEMENTAL_2NDHANDCONTROLLER\n" );
  313. break;
  314. case DI8DEVTYPESUPPLEMENTAL_HEADTRACKER:
  315. DevMsg( "DI8DEVTYPESUPPLEMENTAL_HEADTRACKER\n" );
  316. break;
  317. case DI8DEVTYPESUPPLEMENTAL_HANDTRACKER:
  318. DevMsg( "DI8DEVTYPESUPPLEMENTAL_HANDTRACKER\n" );
  319. break;
  320. case DI8DEVTYPESUPPLEMENTAL_SHIFTSTICKGATE:
  321. DevMsg( "DI8DEVTYPESUPPLEMENTAL_SHIFTSTICKGATE\n" );
  322. break;
  323. case DI8DEVTYPESUPPLEMENTAL_SHIFTER:
  324. DevMsg( "DI8DEVTYPESUPPLEMENTAL_SHIFTER\n" );
  325. break;
  326. case DI8DEVTYPESUPPLEMENTAL_THROTTLE:
  327. DevMsg( "DI8DEVTYPESUPPLEMENTAL_THROTTLE\n" );
  328. break;
  329. case DI8DEVTYPESUPPLEMENTAL_SPLITTHROTTLE:
  330. DevMsg( "DI8DEVTYPESUPPLEMENTAL_SPLITTHROTTLE\n" );
  331. break;
  332. case DI8DEVTYPESUPPLEMENTAL_COMBINEDPEDALS:
  333. DevMsg( "DI8DEVTYPESUPPLEMENTAL_COMBINEDPEDALS\n" );
  334. break;
  335. case DI8DEVTYPESUPPLEMENTAL_DUALPEDALS:
  336. DevMsg( "DI8DEVTYPESUPPLEMENTAL_DUALPEDALS\n" );
  337. break;
  338. case DI8DEVTYPESUPPLEMENTAL_THREEPEDALS:
  339. DevMsg( "DI8DEVTYPESUPPLEMENTAL_THREEPEDALS\n" );
  340. break;
  341. case DI8DEVTYPESUPPLEMENTAL_RUDDERPEDALS:
  342. DevMsg( "DI8DEVTYPESUPPLEMENTAL_RUDDERPEDALS\n" );
  343. break;
  344. }
  345. break;
  346. }
  347. }
  348. static void DescribeFFDevice( const DIDEVCAPS& caps )
  349. {
  350. ReportCap( caps.dwFlags, DIDC_ALIAS, " DIDC_ALIAS" );
  351. ReportCap( caps.dwFlags, DIDC_ATTACHED, " device is attached" );
  352. ReportCap( caps.dwFlags, DIDC_DEADBAND, " device supports deadband" );
  353. //ReportCap( caps.dwFlags, DIDC_EMULATED, " device is emulated" );
  354. ReportCap( caps.dwFlags, DIDC_FFFADE, " device supports fade" );
  355. ReportCap( caps.dwFlags, DIDC_FFATTACK, " device supports attack" );
  356. ReportCap( caps.dwFlags, DIDC_HIDDEN, " DIDC_HIDDEN" );
  357. ReportCap( caps.dwFlags, DIDC_PHANTOM, " DIDC_PHANTOM" );
  358. ReportCap( caps.dwFlags, DIDC_POLLEDDATAFORMAT, " device using polled data format" );
  359. ReportCap( caps.dwFlags, DIDC_POLLEDDEVICE, " device is polled" );
  360. ReportCap( caps.dwFlags, DIDC_POSNEGCOEFFICIENTS, " device supports two coefficient values for conditions" );
  361. ReportCap( caps.dwFlags, DIDC_POSNEGSATURATION, " DIDC_POSNEGSATURATION" );
  362. ReportCap( caps.dwFlags, DIDC_SATURATION, " device supports saturation" );
  363. ReportCap( caps.dwFlags, DIDC_STARTDELAY, " device supports start delay" );
  364. ReportDevType( caps.dwDevType );
  365. DevMsg( " %u buttons\n", caps.dwButtons );
  366. DevMsg( " %u axes\n", caps.dwAxes );
  367. DevMsg( " %u POVs\n", caps.dwPOVs );
  368. DevMsg( " %.1f msec FF sample period\n", (float)caps.dwFFSamplePeriod/1000.0f );
  369. DevMsg( " %.1f msec FF min time resolution period\n", (float)caps.dwFFMinTimeResolution/1000.0f );
  370. }
  371. struct LoadEffectContext_t
  372. {
  373. LPDIRECTINPUTDEVICE8 device;
  374. EffectMap_t *map;
  375. };
  376. static BOOL CALLBACK EnumEffectsInFileProc(LPCDIFILEEFFECT lpdife, LPVOID pvRef)
  377. {
  378. LoadEffectContext_t *ctx = ( LoadEffectContext_t * )pvRef;
  379. EffectMap_t *map = ctx->map;
  380. vecEffectPtr_t *vecPtr = map->pVecEffectPtr;
  381. Assert( vecPtr );
  382. int idx = vecPtr->AddToTail( NULL );
  383. HRESULT hr;
  384. hr = ctx->device->CreateEffect
  385. (
  386. lpdife->GuidEffect,
  387. lpdife->lpDiEffect,
  388. &(*vecPtr)[ idx ],
  389. NULL
  390. );
  391. if ( FAILED ( hr ) )
  392. {
  393. // Error handling
  394. Msg( "EnumEffectsInFileProc during effect loading for %s\n", map->effectfile );
  395. }
  396. return DIENUM_CONTINUE;
  397. }
  398. //-----------------------------------------------------------------------------
  399. // Purpose:
  400. // Input : device -
  401. // &map -
  402. // Output : static void
  403. //-----------------------------------------------------------------------------
  404. static void LoadEffectFile( LPDIRECTINPUTDEVICE8 device, EffectMap_t &map )
  405. {
  406. LoadEffectContext_t context;
  407. context.device = device;
  408. context.map = &map;
  409. // Pull out of .gcf if needed
  410. filesystem->GetLocalCopy( map.effectfile );
  411. char fullpath[ 512 ];
  412. filesystem->GetLocalPath( map.effectfile, fullpath, sizeof( fullpath ) );
  413. HRESULT hr = device->EnumEffectsInFile
  414. ( fullpath,
  415. EnumEffectsInFileProc,
  416. (LPVOID)&context,
  417. DIFEF_MODIFYIFNEEDED );
  418. if ( FAILED( hr ) )
  419. {
  420. Msg( "EnumEffectsInFile failed for %s\n", map.effectfile );
  421. }
  422. }
  423. //-----------------------------------------------------------------------------
  424. // Purpose:
  425. // Input : device -
  426. // Output : static void
  427. //-----------------------------------------------------------------------------
  428. static void LoadEffectFiles( LPDIRECTINPUTDEVICE8 device )
  429. {
  430. int c = ARRAYSIZE( g_EffectMap );
  431. for ( int i = 0; i < c; ++i )
  432. {
  433. EffectMap_t& map = g_EffectMap[ i ];
  434. LoadEffectFile( device, map );
  435. }
  436. }
  437. //-----------------------------------------------------------------------------
  438. // Purpose: Init_ForceFeedback
  439. //-----------------------------------------------------------------------------
  440. void CInput::Init_ForceFeedback()
  441. {
  442. // abort startup if user requests no joystick
  443. if ( CommandLine()->FindParm("-noff" ) )
  444. {
  445. return;
  446. }
  447. Assert( !m_pFF );
  448. m_pFF = new ForceFeedbackParams_t;
  449. Assert( m_pFF );
  450. Q_memset( m_pFF, 0, sizeof( *m_pFF ) );
  451. HRESULT hr = DirectInput8Create(GetModuleHandle(0), DIRECTINPUT_VERSION,
  452. IID_IDirectInput8, (void**)&m_pFF->m_pIInput, NULL );
  453. if ( FAILED( hr ) )
  454. {
  455. return;
  456. }
  457. hr = m_pFF->m_pIInput->CreateDevice(GUID_Joystick, &m_pFF->m_pIJoystick, NULL );
  458. if ( FAILED( hr ) )
  459. {
  460. return;
  461. }
  462. hr = m_pFF->m_pIJoystick->SetDataFormat(&c_dfDIJoystick2 );
  463. if ( FAILED( hr ) )
  464. {
  465. return;
  466. }
  467. HWND mainWnd = (HWND)g_pEngineWindow->GetWindowHandle();
  468. hr = m_pFF->m_pIJoystick->SetCooperativeLevel( mainWnd, DISCL_BACKGROUND | DISCL_EXCLUSIVE );
  469. if ( FAILED( hr ) )
  470. {
  471. return;
  472. }
  473. DIPROPDWORD dwd;
  474. //The following code turns the center spring off
  475. dwd.diph.dwSize = sizeof(DIPROPDWORD);
  476. dwd.diph.dwHeaderSize = sizeof(DIPROPHEADER);
  477. dwd.diph.dwObj = 0;
  478. dwd.diph.dwHow = DIPH_DEVICE;
  479. dwd.dwData = FALSE;
  480. if ( !ff_autocenter.GetBool() )
  481. {
  482. hr = m_pFF->m_pIJoystick->SetProperty( DIPROP_AUTOCENTER, &dwd.diph );
  483. if ( FAILED( hr ) )
  484. {
  485. return;
  486. }
  487. }
  488. // Acquire the device
  489. hr = m_pFF->m_pIJoystick->Acquire();
  490. if( FAILED( hr ) )
  491. {
  492. return;
  493. }
  494. DIDEVCAPS diDevCaps;
  495. Q_memset( &diDevCaps, 0, sizeof( diDevCaps ) );
  496. diDevCaps.dwSize = sizeof( diDevCaps );
  497. hr = m_pFF->m_pIJoystick->GetCapabilities( &diDevCaps );
  498. if ( FAILED( hr ) )
  499. {
  500. DevMsg( "GetCapabilities failed\n" );
  501. return;
  502. }
  503. if ( !( diDevCaps.dwFlags & DIDC_FORCEFEEDBACK ) )
  504. {
  505. // Doesn't support FF
  506. return;
  507. }
  508. DIDEVICEINSTANCE diDI;
  509. Q_memset( &diDI, 0, sizeof( diDI ) );
  510. diDI.dwSize = sizeof( diDI );
  511. hr = m_pFF->m_pIJoystick->GetDeviceInfo( &diDI );
  512. if ( FAILED( hr ) )
  513. {
  514. DevMsg( "GetDeviceInfo failed\n" );
  515. return;
  516. }
  517. DevMsg( "Forcefeedback device found:\n" );
  518. //DevMsg( " device '%s'\n", diDI.tszInstanceName );
  519. DevMsg( " product '%s'\n", diDI.tszProductName );
  520. DescribeFFDevice( diDevCaps );
  521. InitEffectMap();
  522. LoadEffectFiles( m_pFF->m_pIJoystick );
  523. m_pFF->m_bForceFeedbackAvailable = true;
  524. }
  525. //-----------------------------------------------------------------------------
  526. // Purpose: Shutdown_ForceFeedback
  527. //-----------------------------------------------------------------------------
  528. void CInput::Shutdown_ForceFeedback()
  529. {
  530. HRESULT hr;
  531. Assert( m_pFF );
  532. if ( !m_pFF )
  533. {
  534. return;
  535. }
  536. if ( m_pFF->m_bForceFeedbackAvailable )
  537. {
  538. m_pFF->m_bForceFeedbackAvailable = false;
  539. ShutdownEffectMap();
  540. // Do cleanup
  541. if ( m_pFF->m_pIJoystick )
  542. {
  543. hr = m_pFF->m_pIJoystick->Unacquire();
  544. if ( FAILED( hr ) )
  545. {
  546. DevMsg( "Forcefeedback Unacquire failed\n" );
  547. }
  548. hr = m_pFF->m_pIJoystick->Release();
  549. if ( FAILED( hr ) )
  550. {
  551. DevMsg( "Forcefeedback Release failed\n" );
  552. }
  553. }
  554. if ( m_pFF->m_pIInput )
  555. {
  556. hr = m_pFF->m_pIInput->Release();
  557. if ( FAILED( hr ) )
  558. {
  559. DevMsg( "DirectInput Release failed\n" );
  560. }
  561. }
  562. }
  563. delete m_pFF;
  564. m_pFF = NULL;
  565. }
  566. //-----------------------------------------------------------------------------
  567. // Purpose:
  568. //-----------------------------------------------------------------------------
  569. void CInput::ForceFeedback_Reaquire()
  570. {
  571. if ( !m_pFF || !m_pFF->m_bForceFeedbackAvailable )
  572. return;
  573. HRESULT hr = m_pFF->m_pIJoystick->Acquire();
  574. if ( FAILED( hr ) )
  575. {
  576. DevMsg( "ForceFeedback_Reaquire failed\n" );
  577. }
  578. }
  579. //-----------------------------------------------------------------------------
  580. // Purpose: Certain devices require polling periodically
  581. //-----------------------------------------------------------------------------
  582. void CInput::ForceFeedback_Think()
  583. {
  584. if ( !m_pFF || !m_pFF->m_bForceFeedbackAvailable )
  585. return;
  586. HRESULT hr = m_pFF->m_pIJoystick->Poll();
  587. if ( FAILED( hr ) )
  588. {
  589. if ( hr == DIERR_INPUTLOST ||
  590. hr == DIERR_NOTACQUIRED )
  591. {
  592. ForceFeedback_Reaquire();
  593. }
  594. }
  595. }
  596. //-----------------------------------------------------------------------------
  597. // Purpose:
  598. //-----------------------------------------------------------------------------
  599. void CInput::ForceFeedback_StopAll()
  600. {
  601. if ( !m_pFF || !m_pFF->m_bForceFeedbackAvailable )
  602. return;
  603. HRESULT hr = m_pFF->m_pIJoystick->SendForceFeedbackCommand( DISFFC_STOPALL );
  604. if ( hr == DIERR_INPUTLOST )
  605. {
  606. ForceFeedback_Reaquire();
  607. }
  608. }
  609. //-----------------------------------------------------------------------------
  610. // Purpose:
  611. //-----------------------------------------------------------------------------
  612. void CInput::ForceFeedback_Pause()
  613. {
  614. if ( !m_pFF || !m_pFF->m_bForceFeedbackAvailable )
  615. return;
  616. m_pFF->m_bPaused = true;
  617. HRESULT hr = m_pFF->m_pIJoystick->SendForceFeedbackCommand( DISFFC_PAUSE );
  618. if ( hr == DIERR_INPUTLOST )
  619. {
  620. ForceFeedback_Reaquire();
  621. }
  622. }
  623. //-----------------------------------------------------------------------------
  624. // Purpose:
  625. //-----------------------------------------------------------------------------
  626. void CInput::ForceFeedback_Resume()
  627. {
  628. if ( !m_pFF || !m_pFF->m_bForceFeedbackAvailable )
  629. return;
  630. if ( !m_pFF->m_bPaused )
  631. return;
  632. m_pFF->m_bPaused = false;
  633. HRESULT hr = m_pFF->m_pIJoystick->SendForceFeedbackCommand( DISFFC_CONTINUE );
  634. if ( hr == DIERR_INPUTLOST )
  635. {
  636. ForceFeedback_Reaquire();
  637. }
  638. }
  639. //-----------------------------------------------------------------------------
  640. // Purpose:
  641. // Input : effectnum -
  642. // params -
  643. //-----------------------------------------------------------------------------
  644. void CInput::ForceFeedback_Start( int effectnum, const FFBaseParams_t& params )
  645. {
  646. if ( !m_pFF || !m_pFF->m_bForceFeedbackAvailable )
  647. return;
  648. // Unpause system...
  649. if ( m_pFF->m_bPaused )
  650. {
  651. ForceFeedback_Resume();
  652. }
  653. // look up the effect
  654. FORCEFEEDBACK_t effect = (FORCEFEEDBACK_t)effectnum;
  655. if ( effect < 0 || effect >= NUM_FORCE_FEEDBACK_PRESETS )
  656. {
  657. Assert( !"ForceFeedback_Start with bogus effectnum" );
  658. return;
  659. }
  660. EffectMap_t *map = &g_EffectMap[ effectnum ];
  661. vecEffectPtr_t *effects = map->pVecEffectPtr;
  662. // Play the effects on the device
  663. int c = effects->Count();
  664. for ( int i = 0; i < c; ++i )
  665. {
  666. LPDIRECTINPUTEFFECT pEffect = (*effects)[ i ];
  667. if ( !map->m_bDownloaded )
  668. {
  669. pEffect->Download();
  670. map->m_bDownloaded = true;
  671. }
  672. DWORD flags = DIEP_DIRECTION | DIEP_GAIN | DIEP_DURATION;
  673. LONG rglDirection[2] = { 0, 100 };
  674. // Fill in parameters
  675. DIEFFECT effect;
  676. Q_memset( &effect, 0, sizeof( effect ) );
  677. effect.dwSize = sizeof( effect );
  678. effect.dwFlags = DIEFF_POLAR | DIEFF_OBJECTOFFSETS;
  679. effect.rglDirection = rglDirection;
  680. effect.cAxes = 2;
  681. HRESULT hr = pEffect->GetParameters( &effect, flags );
  682. if ( !FAILED( hr ) )
  683. {
  684. // If params.m_flDuration == 0.0f then that means use the duration in the file
  685. if ( params.m_flDuration <= -0.999f )
  686. {
  687. effect.dwDuration = INFINITE;
  688. }
  689. else if( params.m_flDuration >= 0.001f )
  690. {
  691. // Convert to microsseconds
  692. effect.dwDuration = (DWORD)( params.m_flDuration * 1000000.0f );
  693. }
  694. effect.dwGain = params.m_flGain * 10000.0f;
  695. effect.rglDirection[ 0 ] = 100.0f * params.m_flDirection;
  696. effect.rglDirection[ 1 ] = 0;
  697. hr = pEffect->SetParameters( &effect, flags );
  698. if ( !FAILED( hr ) )
  699. {
  700. pEffect->Start( 1, params.m_bSolo ? DIES_SOLO : 0 );
  701. }
  702. }
  703. }
  704. }
  705. //-----------------------------------------------------------------------------
  706. // Purpose:
  707. // Input : effectnum -
  708. //-----------------------------------------------------------------------------
  709. void CInput::ForceFeedback_Stop( int effectnum )
  710. {
  711. if ( !m_pFF || !m_pFF->m_bForceFeedbackAvailable )
  712. return;
  713. // look up the effect
  714. FORCEFEEDBACK_t effect = (FORCEFEEDBACK_t)effectnum;
  715. if ( effect < 0 || effect >= NUM_FORCE_FEEDBACK_PRESETS )
  716. {
  717. Assert( !"ForceFeedback_Stop with bogus effectnum" );
  718. return;
  719. }
  720. EffectMap_t *map = &g_EffectMap[ effectnum ];
  721. vecEffectPtr_t *effects = map->pVecEffectPtr;
  722. // Stop the effects on the device
  723. int c = effects->Count();
  724. for ( int i = 0; i < c; ++i )
  725. {
  726. LPDIRECTINPUTEFFECT pEffect = (*effects)[ i ];
  727. pEffect->Stop();
  728. }
  729. }