joystick.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480
  1. #include "pch.h"
  2. #include "joystick.h"
  3. #include "memory.h"
  4. LPDIRECTINPUTDEVICE Joystick::s_pDevice = NULL;
  5. LPDIRECTINPUTDEVICE2 Joystick::s_pDevice2 = NULL;
  6. LPDIRECTINPUT Joystick::s_pDirectInput = NULL;
  7. LPDIRECTINPUTEFFECT Joystick::s_pEffectBounce = NULL;
  8. LPDIRECTINPUTEFFECT Joystick::s_pEffectFire = NULL;
  9. LPDIRECTINPUTEFFECT Joystick::s_pEffectExplode = NULL;
  10. bool Joystick::s_fSupportForceFeedback = false;
  11. void Joystick::Terminate()
  12. {
  13. if (s_pEffectBounce)
  14. s_pEffectBounce->Release();
  15. if (s_pEffectFire)
  16. s_pEffectFire->Release();
  17. if (s_pEffectExplode)
  18. s_pEffectExplode->Release();
  19. if (s_pDevice)
  20. {
  21. s_pDevice->Unacquire();
  22. s_pDevice->Release();
  23. }
  24. if (s_pDevice2)
  25. s_pDevice2->Release();
  26. if (s_pDirectInput)
  27. s_pDirectInput->Release();
  28. }
  29. void Joystick::Flush(void)
  30. {
  31. // Do things this way because, ahem... SetKeyboardState() doesn't appear
  32. // to work on Win'95...
  33. for (int x=0; x<256; x++)
  34. {
  35. GetKeyboard(x);
  36. }
  37. }
  38. int Joystick::QKeyboard(void)
  39. {
  40. // if there is a keyboard, returns 1 else 0
  41. return 0;
  42. }
  43. int Joystick::QMouse(void)
  44. {
  45. // if no mouse, 0 else number of buttons on mouse
  46. return 0;
  47. }
  48. int Joystick::QJoystick(void)
  49. {
  50. // if no joystick(s), returns 0 else number of joysticks attached.
  51. return 1;
  52. }
  53. int Joystick::GetKeyboard(int key)
  54. {
  55. // returns 0 if the key has been depressed, else returns 1 and sets key to code recd.
  56. //return (GetAsyncKeyState(key) != 0);
  57. return GetKeyState(key) & (~1);
  58. }
  59. int Joystick::QKeyDepressed(int numkeys, int *keyarray)
  60. {
  61. int x;
  62. // tells if keys in keyarray are currently depressed. Returns 0 if not, 1 if all
  63. if (!numkeys || !keyarray)
  64. return(0);
  65. for (x=0; x<numkeys ; x++)
  66. {
  67. // mask off top bit
  68. if ((GetAsyncKeyState(keyarray[x])) == 0)
  69. return(0);
  70. }
  71. return(1);
  72. }
  73. int Joystick::GetMouse(int& xpos, int&ypos, int& buttons)
  74. {
  75. /* // returns 0 if no mouse action to report; else, 1 and fills in params
  76. int button1, button2;
  77. POINT pt;
  78. if (!GetCursorPos(&pt))
  79. return(0);
  80. xpos = pt.x;
  81. ypos = pt.y;
  82. buttons = 0;
  83. button1 = GetAsyncKeyState(VK_LBUTTON);
  84. button2 = GetAsyncKeyState(VK_RBUTTON);
  85. if (button1)
  86. buttons |= 1;
  87. if (button2)
  88. buttons |= 2;
  89. return(1); */
  90. return 0;
  91. }
  92. int normalize (int val, int minval, int maxval);
  93. bool Joystick::Initialize(HINSTANCE hInst, HWND hWnd)
  94. {
  95. HRESULT hr;
  96. DIDEVCAPS didc;
  97. GUID guidDevice;
  98. // create the base DirectInput object
  99. if (FAILED(hr = DirectInputCreate(hInst, DIRECTINPUT_VERSION, &s_pDirectInput, NULL)))
  100. return false;
  101. // enumerate for joystick devices
  102. if (FAILED(hr = s_pDirectInput->EnumDevices(DIDEVTYPE_JOYSTICK,
  103. (LPDIENUMDEVICESCALLBACK)EnumDeviceProc,
  104. &guidDevice, DIEDFL_ATTACHEDONLY)))
  105. return false;
  106. // get the joystick
  107. if (FAILED(hr = s_pDirectInput->CreateDevice(guidDevice, &s_pDevice, NULL)))
  108. return false;
  109. // need InputDevice2 for Force Feedback
  110. if (FAILED(hr = s_pDevice->QueryInterface(
  111. IID_IDirectInputDevice2, (void**)&s_pDevice2)))
  112. return false;
  113. // This tells the device object to act like a specific device -- in our case, like a joystick
  114. if (FAILED(hr = s_pDevice->SetDataFormat(&c_dfDIJoystick)))
  115. return false;
  116. // ForceFeedback requires Exclusive access to the device.
  117. if (FAILED(hr = s_pDevice->SetCooperativeLevel(hWnd,
  118. DISCL_EXCLUSIVE | DISCL_FOREGROUND)))
  119. return false;
  120. // set ranges, deadzones, etc.
  121. if (!PrepareDevice())
  122. return false;
  123. // get the device capabilities
  124. didc.dwSize = sizeof(DIDEVCAPS);
  125. if (FAILED(hr = s_pDevice->GetCapabilities(&didc)))
  126. return false;
  127. if (didc.dwFlags & DIDC_FORCEFEEDBACK)
  128. {
  129. s_fSupportForceFeedback = true;
  130. if (!CreateEffects())
  131. return false;
  132. }
  133. Flush();
  134. return true;
  135. }
  136. BOOL CALLBACK Joystick::EnumDeviceProc(LPDIDEVICEINSTANCE pdidi, LPVOID pv)
  137. {
  138. GUID *pguidDevice = NULL;
  139. // report back the instance guid of the device we enumerated
  140. if(pv)
  141. {
  142. pguidDevice = (GUID *)pv;
  143. *pguidDevice = pdidi->guidInstance;
  144. }
  145. // BUGBUG for now, stop after the first device has been found
  146. return DIENUM_STOP;
  147. }
  148. BOOL CALLBACK Joystick::EnumEffectTypeProc(LPCDIEFFECTINFO pei, LPVOID pv)
  149. {
  150. GUID *pguidEffect = NULL;
  151. // report back the guid of the effect we enumerated
  152. if(pv)
  153. {
  154. pguidEffect = (GUID *)pv;
  155. *pguidEffect = pei->guid;
  156. }
  157. // BUGBUG - look at this some more....
  158. return DIENUM_STOP;
  159. }
  160. bool Joystick::AcquireDevice()
  161. {
  162. if (!s_pDevice)
  163. return false;
  164. // reacquire the device
  165. if (FAILED(s_pDevice->Acquire()))
  166. return false;
  167. if (!CreateEffects())
  168. return false;
  169. return false;
  170. }
  171. bool Joystick::CreateEffects()
  172. {
  173. GUID guidEffect;
  174. DIEFFECT diEffect;
  175. DIENVELOPE diEnvelope;
  176. DWORD rgdwAxes[2];
  177. LONG rglDirections[2];
  178. DICONSTANTFORCE dicf;
  179. DIPERIODIC dipf;
  180. // make sure that we have a non-NULL device object
  181. if (!s_pDevice2)
  182. return false;
  183. // initialize DIEFFECT and DIENVELOPE structures
  184. memset(&diEffect, 0, sizeof(DIEFFECT));
  185. memset(&diEnvelope, 0, sizeof(DIENVELOPE));
  186. // these fields are the same for all effects we will be creating
  187. diEffect.dwSize = sizeof(DIEFFECT);
  188. diEffect.dwSamplePeriod = 0; // use default sample period
  189. diEffect.dwTriggerButton = DIEB_NOTRIGGER;
  190. diEffect.dwTriggerRepeatInterval = 0;
  191. diEffect.rgdwAxes = rgdwAxes;
  192. diEffect.rglDirection = rglDirections;
  193. diEffect.dwGain = 7500; // todo: gain selected by user
  194. // both the "bounce" and "fire" effects will be based on the first
  195. // constant force effect enumerated
  196. if (FAILED(s_pDevice2->EnumEffects(
  197. (LPDIENUMEFFECTSCALLBACK)EnumEffectTypeProc,
  198. &guidEffect, DIEFT_CONSTANTFORCE)))
  199. return false;
  200. // (Re)create the bounce effect
  201. if (s_pEffectBounce)
  202. {
  203. s_pEffectBounce->Release();
  204. s_pEffectBounce= NULL;
  205. }
  206. dicf.lMagnitude = 10000;
  207. rgdwAxes[0] = DIJOFS_X;
  208. rgdwAxes[1] = DIJOFS_Y;
  209. rglDirections[0] = 0;
  210. rglDirections[1] = 0;
  211. diEffect.dwFlags = DIEFF_OBJECTOFFSETS | DIEFF_POLAR;
  212. diEffect.dwDuration = 200000;
  213. diEffect.cAxes = 2;
  214. diEffect.lpEnvelope = NULL;
  215. diEffect.cbTypeSpecificParams = sizeof(DICONSTANTFORCE);
  216. diEffect.lpvTypeSpecificParams = &dicf;
  217. if (FAILED(s_pDevice2->CreateEffect(guidEffect,
  218. &diEffect, &s_pEffectBounce, NULL)))
  219. return false;
  220. // (Re)create the fire effect
  221. if (s_pEffectFire)
  222. {
  223. s_pEffectFire->Release();
  224. s_pEffectFire = NULL;
  225. }
  226. dicf.lMagnitude = 10000;
  227. rgdwAxes[0] = DIJOFS_Y;
  228. rglDirections[0] = 1;
  229. diEffect.dwFlags = DIEFF_OBJECTOFFSETS | DIEFF_CARTESIAN;
  230. diEffect.dwDuration = 20000;
  231. diEffect.cAxes = 1;
  232. diEffect.lpEnvelope = NULL;
  233. diEffect.cbTypeSpecificParams = sizeof(DICONSTANTFORCE);
  234. diEffect.lpvTypeSpecificParams = &dicf;
  235. if (FAILED(s_pDevice2->CreateEffect(guidEffect,
  236. &diEffect, &s_pEffectFire, NULL)))
  237. return false;
  238. // the "explode" effect will be based on the first
  239. // periodic effect enumerated
  240. if (FAILED(s_pDevice2->EnumEffects(
  241. (LPDIENUMEFFECTSCALLBACK)EnumEffectTypeProc,
  242. &guidEffect, DIEFT_PERIODIC)))
  243. return false;
  244. // (Re)create the explode effect
  245. if (s_pEffectExplode)
  246. {
  247. s_pEffectExplode->Release();
  248. s_pEffectExplode = NULL;
  249. }
  250. // We want to shape the explode effect so that it starts
  251. // at it's peak and then fades out
  252. diEnvelope.dwSize = sizeof(DIENVELOPE);
  253. diEnvelope.dwAttackLevel = 0;
  254. diEnvelope.dwAttackTime = 0;
  255. diEnvelope.dwFadeLevel = 0;
  256. diEnvelope.dwFadeTime = 1000000;
  257. dipf.dwMagnitude = 10000;
  258. dipf.lOffset = 0;
  259. dipf.dwPhase = 0;
  260. dipf.dwPeriod = 100000;
  261. rgdwAxes[0] = DIJOFS_X;
  262. rglDirections[0] = 0;
  263. diEffect.dwFlags = DIEFF_OBJECTOFFSETS | DIEFF_CARTESIAN;
  264. diEffect.dwDuration = 1000000;
  265. diEffect.cAxes = 1;
  266. diEffect.lpEnvelope = &diEnvelope;
  267. diEffect.cbTypeSpecificParams = sizeof(DIPERIODIC);
  268. diEffect.lpvTypeSpecificParams = &dipf;
  269. if (FAILED(s_pDevice2->CreateEffect(guidEffect,
  270. &diEffect, &s_pEffectExplode, NULL)))
  271. return false;
  272. return true;
  273. }
  274. bool Joystick::GetJoystick(DIJOYSTATE* pdijs)
  275. {
  276. HRESULT hr;
  277. DWORD dwInput = 0;
  278. memset(pdijs, 0, sizeof(DIJOYSTATE));
  279. if (!s_pDevice)
  280. return false;
  281. if (s_pDevice2)
  282. hr = s_pDevice2->Poll();
  283. hr = s_pDevice->GetDeviceState(sizeof(DIJOYSTATE), pdijs);
  284. if (FAILED(hr))
  285. {
  286. if ((hr == DIERR_INPUTLOST))
  287. {
  288. AcquireDevice();
  289. }
  290. else
  291. AcquireDevice();
  292. return true;
  293. }
  294. return true;
  295. }
  296. bool Joystick::PrepareDevice()
  297. {
  298. DIPROPRANGE dipr;
  299. // quick check to make sure that the object pointer is non-NULL
  300. if(!s_pDevice)
  301. return false;
  302. s_pDevice->Unacquire();
  303. // set the axis ranges for the device
  304. dipr.diph.dwSize = sizeof(DIPROPRANGE);
  305. dipr.diph.dwHeaderSize = sizeof(dipr.diph);
  306. dipr.diph.dwHow = DIPH_BYOFFSET;
  307. dipr.lMin = -100; // negative to the left/top
  308. dipr.lMax = 100; // positive to the right/bottom
  309. dipr.diph.dwObj = DIJOFS_X;
  310. if (FAILED(s_pDevice->SetProperty(DIPROP_RANGE, &dipr.diph)))
  311. return false;
  312. dipr.diph.dwObj = DIJOFS_Y;
  313. if (FAILED(s_pDevice->SetProperty(DIPROP_RANGE, &dipr.diph)))
  314. return false;
  315. dipr.diph.dwObj = DIJOFS_Z;
  316. if (FAILED(s_pDevice->SetProperty(DIPROP_RANGE, &dipr.diph)))
  317. return false;
  318. dipr.diph.dwObj = DIJOFS_RZ;
  319. if (FAILED(s_pDevice->SetProperty(DIPROP_RANGE, &dipr.diph)))
  320. return false;
  321. /*
  322. dipr.diph.dwObj = DIJOFS_RX;
  323. if (FAILED(s_pDevice->SetProperty(DIPROP_RANGE, &dipr.diph)))
  324. return false;
  325. dipr.diph.dwObj = DIJOFS_RY;
  326. if (FAILED(s_pDevice->SetProperty(DIPROP_RANGE, &dipr.diph)))
  327. return false;
  328. dipr.diph.dwObj = DIJOFS_SLIDER(0);
  329. if (FAILED(s_pDevice->SetProperty(DIPROP_RANGE, &dipr.diph)))
  330. return false;
  331. dipr.diph.dwObj = DIJOFS_SLIDER(1);
  332. if (FAILED(s_pDevice->SetProperty(DIPROP_RANGE, &dipr.diph)))
  333. return false;
  334. */
  335. AcquireDevice();
  336. return true;
  337. }
  338. bool Joystick::PlayFFEffect(EffectID effectID, LONG lDirection)
  339. {
  340. DIEFFECT diEffect;
  341. LONG rglDirections[2] = { 0, 0 };
  342. // initialize DIEFFECT structure
  343. memset(&diEffect, 0, sizeof(DIEFFECT));
  344. diEffect.dwSize = sizeof(DIEFFECT);
  345. switch (effectID)
  346. {
  347. case effectBounce:
  348. if(s_pEffectBounce)
  349. {
  350. rglDirections[0] = lDirection * 100;
  351. diEffect.dwFlags = DIEFF_OBJECTOFFSETS | DIEFF_POLAR;
  352. diEffect.cAxes = 2;
  353. diEffect.rglDirection = rglDirections;
  354. if (FAILED(s_pEffectBounce->SetParameters(&diEffect, DIEP_DIRECTION)))
  355. return false;
  356. // play the effect
  357. if (FAILED(s_pEffectBounce->Start(1, 0)))
  358. return false;
  359. }
  360. break;
  361. case effectFire:
  362. if(s_pEffectFire)
  363. {
  364. if (FAILED(s_pEffectFire->Start(1, 0)))
  365. return false;
  366. }
  367. break;
  368. case effectExplode:
  369. if (s_pEffectExplode)
  370. {
  371. if (FAILED(s_pEffectExplode->Start(1, 0)))
  372. return false;
  373. }
  374. break;
  375. }
  376. return true;
  377. }