in_win.c 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233
  1. /*
  2. Copyright (C) 1996-1997 Id Software, Inc.
  3. This program is free software; you can redistribute it and/or
  4. modify it under the terms of the GNU General Public License
  5. as published by the Free Software Foundation; either version 2
  6. of the License, or (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. See the GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program; if not, write to the Free Software
  13. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  14. */
  15. // in_win.c -- windows 95 mouse and joystick code
  16. // 02/21/97 JCB Added extended DirectInput code to support external controllers.
  17. #include <dinput.h>
  18. #include "quakedef.h"
  19. #include "winquake.h"
  20. //#include "dosisms.h"
  21. #define DINPUT_BUFFERSIZE 16
  22. #define iDirectInputCreate(a,b,c,d) pDirectInputCreate(a,b,c,d)
  23. HRESULT (WINAPI *pDirectInputCreate)(HINSTANCE hinst, DWORD dwVersion,
  24. LPDIRECTINPUT * lplpDirectInput, LPUNKNOWN punkOuter);
  25. // mouse variables
  26. cvar_t m_filter = {"m_filter","0"};
  27. int mouse_buttons;
  28. int mouse_oldbuttonstate;
  29. POINT current_pos;
  30. int mouse_x, mouse_y, old_mouse_x, old_mouse_y, mx_accum, my_accum;
  31. static qboolean restore_spi;
  32. static int originalmouseparms[3], newmouseparms[3] = {0, 0, 1};
  33. qboolean mouseinitialized;
  34. static qboolean mouseparmsvalid, mouseactivatetoggle;
  35. static qboolean mouseshowtoggle = 1;
  36. static qboolean dinput_acquired;
  37. static unsigned int mstate_di;
  38. unsigned int uiWheelMessage;
  39. qboolean mouseactive;
  40. // joystick defines and variables
  41. // where should defines be moved?
  42. #define JOY_ABSOLUTE_AXIS 0x00000000 // control like a joystick
  43. #define JOY_RELATIVE_AXIS 0x00000010 // control like a mouse, spinner, trackball
  44. #define JOY_MAX_AXES 6 // X, Y, Z, R, U, V
  45. #define JOY_AXIS_X 0
  46. #define JOY_AXIS_Y 1
  47. #define JOY_AXIS_Z 2
  48. #define JOY_AXIS_R 3
  49. #define JOY_AXIS_U 4
  50. #define JOY_AXIS_V 5
  51. enum _ControlList
  52. {
  53. AxisNada = 0, AxisForward, AxisLook, AxisSide, AxisTurn
  54. };
  55. DWORD dwAxisFlags[JOY_MAX_AXES] =
  56. {
  57. JOY_RETURNX, JOY_RETURNY, JOY_RETURNZ, JOY_RETURNR, JOY_RETURNU, JOY_RETURNV
  58. };
  59. DWORD dwAxisMap[JOY_MAX_AXES];
  60. DWORD dwControlMap[JOY_MAX_AXES];
  61. PDWORD pdwRawValue[JOY_MAX_AXES];
  62. // none of these cvars are saved over a session
  63. // this means that advanced controller configuration needs to be executed
  64. // each time. this avoids any problems with getting back to a default usage
  65. // or when changing from one controller to another. this way at least something
  66. // works.
  67. cvar_t in_joystick = {"joystick","0", true};
  68. cvar_t joy_name = {"joyname", "joystick"};
  69. cvar_t joy_advanced = {"joyadvanced", "0"};
  70. cvar_t joy_advaxisx = {"joyadvaxisx", "0"};
  71. cvar_t joy_advaxisy = {"joyadvaxisy", "0"};
  72. cvar_t joy_advaxisz = {"joyadvaxisz", "0"};
  73. cvar_t joy_advaxisr = {"joyadvaxisr", "0"};
  74. cvar_t joy_advaxisu = {"joyadvaxisu", "0"};
  75. cvar_t joy_advaxisv = {"joyadvaxisv", "0"};
  76. cvar_t joy_forwardthreshold = {"joyforwardthreshold", "0.15"};
  77. cvar_t joy_sidethreshold = {"joysidethreshold", "0.15"};
  78. cvar_t joy_pitchthreshold = {"joypitchthreshold", "0.15"};
  79. cvar_t joy_yawthreshold = {"joyyawthreshold", "0.15"};
  80. cvar_t joy_forwardsensitivity = {"joyforwardsensitivity", "-1.0"};
  81. cvar_t joy_sidesensitivity = {"joysidesensitivity", "-1.0"};
  82. cvar_t joy_pitchsensitivity = {"joypitchsensitivity", "1.0"};
  83. cvar_t joy_yawsensitivity = {"joyyawsensitivity", "-1.0"};
  84. cvar_t joy_wwhack1 = {"joywwhack1", "0.0"};
  85. cvar_t joy_wwhack2 = {"joywwhack2", "0.0"};
  86. qboolean joy_avail, joy_advancedinit, joy_haspov;
  87. DWORD joy_oldbuttonstate, joy_oldpovstate;
  88. int joy_id;
  89. DWORD joy_flags;
  90. DWORD joy_numbuttons;
  91. static LPDIRECTINPUT g_pdi;
  92. static LPDIRECTINPUTDEVICE g_pMouse;
  93. static JOYINFOEX ji;
  94. static HINSTANCE hInstDI;
  95. static qboolean dinput;
  96. typedef struct MYDATA {
  97. LONG lX; // X axis goes here
  98. LONG lY; // Y axis goes here
  99. LONG lZ; // Z axis goes here
  100. BYTE bButtonA; // One button goes here
  101. BYTE bButtonB; // Another button goes here
  102. BYTE bButtonC; // Another button goes here
  103. BYTE bButtonD; // Another button goes here
  104. } MYDATA;
  105. static DIOBJECTDATAFORMAT rgodf[] = {
  106. { &GUID_XAxis, FIELD_OFFSET(MYDATA, lX), DIDFT_AXIS | DIDFT_ANYINSTANCE, 0,},
  107. { &GUID_YAxis, FIELD_OFFSET(MYDATA, lY), DIDFT_AXIS | DIDFT_ANYINSTANCE, 0,},
  108. { &GUID_ZAxis, FIELD_OFFSET(MYDATA, lZ), 0x80000000 | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0,},
  109. { 0, FIELD_OFFSET(MYDATA, bButtonA), DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0,},
  110. { 0, FIELD_OFFSET(MYDATA, bButtonB), DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0,},
  111. { 0, FIELD_OFFSET(MYDATA, bButtonC), 0x80000000 | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0,},
  112. { 0, FIELD_OFFSET(MYDATA, bButtonD), 0x80000000 | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0,},
  113. };
  114. #define NUM_OBJECTS (sizeof(rgodf) / sizeof(rgodf[0]))
  115. static DIDATAFORMAT df = {
  116. sizeof(DIDATAFORMAT), // this structure
  117. sizeof(DIOBJECTDATAFORMAT), // size of object data format
  118. DIDF_RELAXIS, // absolute axis coordinates
  119. sizeof(MYDATA), // device data size
  120. NUM_OBJECTS, // number of objects
  121. rgodf, // and here they are
  122. };
  123. // forward-referenced functions
  124. void IN_StartupJoystick (void);
  125. void Joy_AdvancedUpdate_f (void);
  126. void IN_JoyMove (usercmd_t *cmd);
  127. /*
  128. ===========
  129. Force_CenterView_f
  130. ===========
  131. */
  132. void Force_CenterView_f (void)
  133. {
  134. cl.viewangles[PITCH] = 0;
  135. }
  136. /*
  137. ===========
  138. IN_UpdateClipCursor
  139. ===========
  140. */
  141. void IN_UpdateClipCursor (void)
  142. {
  143. if (mouseinitialized && mouseactive && !dinput)
  144. {
  145. ClipCursor (&window_rect);
  146. }
  147. }
  148. /*
  149. ===========
  150. IN_ShowMouse
  151. ===========
  152. */
  153. void IN_ShowMouse (void)
  154. {
  155. if (!mouseshowtoggle)
  156. {
  157. ShowCursor (TRUE);
  158. mouseshowtoggle = 1;
  159. }
  160. }
  161. /*
  162. ===========
  163. IN_HideMouse
  164. ===========
  165. */
  166. void IN_HideMouse (void)
  167. {
  168. if (mouseshowtoggle)
  169. {
  170. ShowCursor (FALSE);
  171. mouseshowtoggle = 0;
  172. }
  173. }
  174. /*
  175. ===========
  176. IN_ActivateMouse
  177. ===========
  178. */
  179. void IN_ActivateMouse (void)
  180. {
  181. mouseactivatetoggle = true;
  182. if (mouseinitialized)
  183. {
  184. if (dinput)
  185. {
  186. if (g_pMouse)
  187. {
  188. if (!dinput_acquired)
  189. {
  190. IDirectInputDevice_Acquire(g_pMouse);
  191. dinput_acquired = true;
  192. }
  193. }
  194. else
  195. {
  196. return;
  197. }
  198. }
  199. else
  200. {
  201. if (mouseparmsvalid)
  202. restore_spi = SystemParametersInfo (SPI_SETMOUSE, 0, newmouseparms, 0);
  203. SetCursorPos (window_center_x, window_center_y);
  204. SetCapture (mainwindow);
  205. ClipCursor (&window_rect);
  206. }
  207. mouseactive = true;
  208. }
  209. }
  210. /*
  211. ===========
  212. IN_SetQuakeMouseState
  213. ===========
  214. */
  215. void IN_SetQuakeMouseState (void)
  216. {
  217. if (mouseactivatetoggle)
  218. IN_ActivateMouse ();
  219. }
  220. /*
  221. ===========
  222. IN_DeactivateMouse
  223. ===========
  224. */
  225. void IN_DeactivateMouse (void)
  226. {
  227. mouseactivatetoggle = false;
  228. if (mouseinitialized)
  229. {
  230. if (dinput)
  231. {
  232. if (g_pMouse)
  233. {
  234. if (dinput_acquired)
  235. {
  236. IDirectInputDevice_Unacquire(g_pMouse);
  237. dinput_acquired = false;
  238. }
  239. }
  240. }
  241. else
  242. {
  243. if (restore_spi)
  244. SystemParametersInfo (SPI_SETMOUSE, 0, originalmouseparms, 0);
  245. ClipCursor (NULL);
  246. ReleaseCapture ();
  247. }
  248. mouseactive = false;
  249. }
  250. }
  251. /*
  252. ===========
  253. IN_RestoreOriginalMouseState
  254. ===========
  255. */
  256. void IN_RestoreOriginalMouseState (void)
  257. {
  258. if (mouseactivatetoggle)
  259. {
  260. IN_DeactivateMouse ();
  261. mouseactivatetoggle = true;
  262. }
  263. // try to redraw the cursor so it gets reinitialized, because sometimes it
  264. // has garbage after the mode switch
  265. ShowCursor (TRUE);
  266. ShowCursor (FALSE);
  267. }
  268. /*
  269. ===========
  270. IN_InitDInput
  271. ===========
  272. */
  273. qboolean IN_InitDInput (void)
  274. {
  275. HRESULT hr;
  276. DIPROPDWORD dipdw = {
  277. {
  278. sizeof(DIPROPDWORD), // diph.dwSize
  279. sizeof(DIPROPHEADER), // diph.dwHeaderSize
  280. 0, // diph.dwObj
  281. DIPH_DEVICE, // diph.dwHow
  282. },
  283. DINPUT_BUFFERSIZE, // dwData
  284. };
  285. if (!hInstDI)
  286. {
  287. hInstDI = LoadLibrary("dinput.dll");
  288. if (hInstDI == NULL)
  289. {
  290. Con_SafePrintf ("Couldn't load dinput.dll\n");
  291. return false;
  292. }
  293. }
  294. if (!pDirectInputCreate)
  295. {
  296. pDirectInputCreate = (void *)GetProcAddress(hInstDI,"DirectInputCreateA");
  297. if (!pDirectInputCreate)
  298. {
  299. Con_SafePrintf ("Couldn't get DI proc addr\n");
  300. return false;
  301. }
  302. }
  303. // register with DirectInput and get an IDirectInput to play with.
  304. hr = iDirectInputCreate(global_hInstance, DIRECTINPUT_VERSION, &g_pdi, NULL);
  305. if (FAILED(hr))
  306. {
  307. return false;
  308. }
  309. // obtain an interface to the system mouse device.
  310. hr = IDirectInput_CreateDevice(g_pdi, &GUID_SysMouse, &g_pMouse, NULL);
  311. if (FAILED(hr))
  312. {
  313. Con_SafePrintf ("Couldn't open DI mouse device\n");
  314. return false;
  315. }
  316. // set the data format to "mouse format".
  317. hr = IDirectInputDevice_SetDataFormat(g_pMouse, &df);
  318. if (FAILED(hr))
  319. {
  320. Con_SafePrintf ("Couldn't set DI mouse format\n");
  321. return false;
  322. }
  323. // set the cooperativity level.
  324. hr = IDirectInputDevice_SetCooperativeLevel(g_pMouse, mainwindow,
  325. DISCL_EXCLUSIVE | DISCL_FOREGROUND);
  326. if (FAILED(hr))
  327. {
  328. Con_SafePrintf ("Couldn't set DI coop level\n");
  329. return false;
  330. }
  331. // set the buffer size to DINPUT_BUFFERSIZE elements.
  332. // the buffer size is a DWORD property associated with the device
  333. hr = IDirectInputDevice_SetProperty(g_pMouse, DIPROP_BUFFERSIZE, &dipdw.diph);
  334. if (FAILED(hr))
  335. {
  336. Con_SafePrintf ("Couldn't set DI buffersize\n");
  337. return false;
  338. }
  339. return true;
  340. }
  341. /*
  342. ===========
  343. IN_StartupMouse
  344. ===========
  345. */
  346. void IN_StartupMouse (void)
  347. {
  348. HDC hdc;
  349. if ( COM_CheckParm ("-nomouse") )
  350. return;
  351. mouseinitialized = true;
  352. if (COM_CheckParm ("-dinput"))
  353. {
  354. dinput = IN_InitDInput ();
  355. if (dinput)
  356. {
  357. Con_SafePrintf ("DirectInput initialized\n");
  358. }
  359. else
  360. {
  361. Con_SafePrintf ("DirectInput not initialized\n");
  362. }
  363. }
  364. if (!dinput)
  365. {
  366. mouseparmsvalid = SystemParametersInfo (SPI_GETMOUSE, 0, originalmouseparms, 0);
  367. if (mouseparmsvalid)
  368. {
  369. if ( COM_CheckParm ("-noforcemspd") )
  370. newmouseparms[2] = originalmouseparms[2];
  371. if ( COM_CheckParm ("-noforcemaccel") )
  372. {
  373. newmouseparms[0] = originalmouseparms[0];
  374. newmouseparms[1] = originalmouseparms[1];
  375. }
  376. if ( COM_CheckParm ("-noforcemparms") )
  377. {
  378. newmouseparms[0] = originalmouseparms[0];
  379. newmouseparms[1] = originalmouseparms[1];
  380. newmouseparms[2] = originalmouseparms[2];
  381. }
  382. }
  383. }
  384. mouse_buttons = 3;
  385. // if a fullscreen video mode was set before the mouse was initialized,
  386. // set the mouse state appropriately
  387. if (mouseactivatetoggle)
  388. IN_ActivateMouse ();
  389. }
  390. /*
  391. ===========
  392. IN_Init
  393. ===========
  394. */
  395. void IN_Init (void)
  396. {
  397. // mouse variables
  398. Cvar_RegisterVariable (&m_filter);
  399. // joystick variables
  400. Cvar_RegisterVariable (&in_joystick);
  401. Cvar_RegisterVariable (&joy_name);
  402. Cvar_RegisterVariable (&joy_advanced);
  403. Cvar_RegisterVariable (&joy_advaxisx);
  404. Cvar_RegisterVariable (&joy_advaxisy);
  405. Cvar_RegisterVariable (&joy_advaxisz);
  406. Cvar_RegisterVariable (&joy_advaxisr);
  407. Cvar_RegisterVariable (&joy_advaxisu);
  408. Cvar_RegisterVariable (&joy_advaxisv);
  409. Cvar_RegisterVariable (&joy_forwardthreshold);
  410. Cvar_RegisterVariable (&joy_sidethreshold);
  411. Cvar_RegisterVariable (&joy_pitchthreshold);
  412. Cvar_RegisterVariable (&joy_yawthreshold);
  413. Cvar_RegisterVariable (&joy_forwardsensitivity);
  414. Cvar_RegisterVariable (&joy_sidesensitivity);
  415. Cvar_RegisterVariable (&joy_pitchsensitivity);
  416. Cvar_RegisterVariable (&joy_yawsensitivity);
  417. Cvar_RegisterVariable (&joy_wwhack1);
  418. Cvar_RegisterVariable (&joy_wwhack2);
  419. Cmd_AddCommand ("force_centerview", Force_CenterView_f);
  420. Cmd_AddCommand ("joyadvancedupdate", Joy_AdvancedUpdate_f);
  421. uiWheelMessage = RegisterWindowMessage ( "MSWHEEL_ROLLMSG" );
  422. IN_StartupMouse ();
  423. IN_StartupJoystick ();
  424. }
  425. /*
  426. ===========
  427. IN_Shutdown
  428. ===========
  429. */
  430. void IN_Shutdown (void)
  431. {
  432. IN_DeactivateMouse ();
  433. IN_ShowMouse ();
  434. if (g_pMouse)
  435. {
  436. IDirectInputDevice_Release(g_pMouse);
  437. g_pMouse = NULL;
  438. }
  439. if (g_pdi)
  440. {
  441. IDirectInput_Release(g_pdi);
  442. g_pdi = NULL;
  443. }
  444. }
  445. /*
  446. ===========
  447. IN_MouseEvent
  448. ===========
  449. */
  450. void IN_MouseEvent (int mstate)
  451. {
  452. int i;
  453. if (mouseactive && !dinput)
  454. {
  455. // perform button actions
  456. for (i=0 ; i<mouse_buttons ; i++)
  457. {
  458. if ( (mstate & (1<<i)) &&
  459. !(mouse_oldbuttonstate & (1<<i)) )
  460. {
  461. Key_Event (K_MOUSE1 + i, true);
  462. }
  463. if ( !(mstate & (1<<i)) &&
  464. (mouse_oldbuttonstate & (1<<i)) )
  465. {
  466. Key_Event (K_MOUSE1 + i, false);
  467. }
  468. }
  469. mouse_oldbuttonstate = mstate;
  470. }
  471. }
  472. /*
  473. ===========
  474. IN_MouseMove
  475. ===========
  476. */
  477. void IN_MouseMove (usercmd_t *cmd)
  478. {
  479. int mx, my;
  480. HDC hdc;
  481. int i;
  482. DIDEVICEOBJECTDATA od;
  483. DWORD dwElements;
  484. HRESULT hr;
  485. if (!mouseactive)
  486. return;
  487. if (dinput)
  488. {
  489. mx = 0;
  490. my = 0;
  491. for (;;)
  492. {
  493. dwElements = 1;
  494. hr = IDirectInputDevice_GetDeviceData(g_pMouse,
  495. sizeof(DIDEVICEOBJECTDATA), &od, &dwElements, 0);
  496. if ((hr == DIERR_INPUTLOST) || (hr == DIERR_NOTACQUIRED))
  497. {
  498. dinput_acquired = true;
  499. IDirectInputDevice_Acquire(g_pMouse);
  500. break;
  501. }
  502. /* Unable to read data or no data available */
  503. if (FAILED(hr) || dwElements == 0)
  504. {
  505. break;
  506. }
  507. /* Look at the element to see what happened */
  508. switch (od.dwOfs)
  509. {
  510. case DIMOFS_X:
  511. mx += od.dwData;
  512. break;
  513. case DIMOFS_Y:
  514. my += od.dwData;
  515. break;
  516. case DIMOFS_BUTTON0:
  517. if (od.dwData & 0x80)
  518. mstate_di |= 1;
  519. else
  520. mstate_di &= ~1;
  521. break;
  522. case DIMOFS_BUTTON1:
  523. if (od.dwData & 0x80)
  524. mstate_di |= (1<<1);
  525. else
  526. mstate_di &= ~(1<<1);
  527. break;
  528. case DIMOFS_BUTTON2:
  529. if (od.dwData & 0x80)
  530. mstate_di |= (1<<2);
  531. else
  532. mstate_di &= ~(1<<2);
  533. break;
  534. }
  535. }
  536. // perform button actions
  537. for (i=0 ; i<mouse_buttons ; i++)
  538. {
  539. if ( (mstate_di & (1<<i)) &&
  540. !(mouse_oldbuttonstate & (1<<i)) )
  541. {
  542. Key_Event (K_MOUSE1 + i, true);
  543. }
  544. if ( !(mstate_di & (1<<i)) &&
  545. (mouse_oldbuttonstate & (1<<i)) )
  546. {
  547. Key_Event (K_MOUSE1 + i, false);
  548. }
  549. }
  550. mouse_oldbuttonstate = mstate_di;
  551. }
  552. else
  553. {
  554. GetCursorPos (&current_pos);
  555. mx = current_pos.x - window_center_x + mx_accum;
  556. my = current_pos.y - window_center_y + my_accum;
  557. mx_accum = 0;
  558. my_accum = 0;
  559. }
  560. if (m_filter.value)
  561. {
  562. mouse_x = (mx + old_mouse_x) * 0.5;
  563. mouse_y = (my + old_mouse_y) * 0.5;
  564. }
  565. else
  566. {
  567. mouse_x = mx;
  568. mouse_y = my;
  569. }
  570. old_mouse_x = mx;
  571. old_mouse_y = my;
  572. mouse_x *= sensitivity.value;
  573. mouse_y *= sensitivity.value;
  574. // add mouse X/Y movement to cmd
  575. if ( (in_strafe.state & 1) || (lookstrafe.value && (in_mlook.state & 1) ))
  576. cmd->sidemove += m_side.value * mouse_x;
  577. else
  578. cl.viewangles[YAW] -= m_yaw.value * mouse_x;
  579. if (in_mlook.state & 1)
  580. V_StopPitchDrift ();
  581. if ( (in_mlook.state & 1) && !(in_strafe.state & 1))
  582. {
  583. cl.viewangles[PITCH] += m_pitch.value * mouse_y;
  584. if (cl.viewangles[PITCH] > 80)
  585. cl.viewangles[PITCH] = 80;
  586. if (cl.viewangles[PITCH] < -70)
  587. cl.viewangles[PITCH] = -70;
  588. }
  589. else
  590. {
  591. if ((in_strafe.state & 1) && noclip_anglehack)
  592. cmd->upmove -= m_forward.value * mouse_y;
  593. else
  594. cmd->forwardmove -= m_forward.value * mouse_y;
  595. }
  596. // if the mouse has moved, force it to the center, so there's room to move
  597. if (mx || my)
  598. {
  599. SetCursorPos (window_center_x, window_center_y);
  600. }
  601. }
  602. /*
  603. ===========
  604. IN_Move
  605. ===========
  606. */
  607. void IN_Move (usercmd_t *cmd)
  608. {
  609. if (ActiveApp && !Minimized)
  610. {
  611. IN_MouseMove (cmd);
  612. IN_JoyMove (cmd);
  613. }
  614. }
  615. /*
  616. ===========
  617. IN_Accumulate
  618. ===========
  619. */
  620. void IN_Accumulate (void)
  621. {
  622. int mx, my;
  623. HDC hdc;
  624. if (mouseactive)
  625. {
  626. GetCursorPos (&current_pos);
  627. mx_accum += current_pos.x - window_center_x;
  628. my_accum += current_pos.y - window_center_y;
  629. // force the mouse to the center, so there's room to move
  630. SetCursorPos (window_center_x, window_center_y);
  631. }
  632. }
  633. /*
  634. ===================
  635. IN_ClearStates
  636. ===================
  637. */
  638. void IN_ClearStates (void)
  639. {
  640. if (mouseactive)
  641. {
  642. mx_accum = 0;
  643. my_accum = 0;
  644. mouse_oldbuttonstate = 0;
  645. }
  646. }
  647. /*
  648. ===============
  649. IN_StartupJoystick
  650. ===============
  651. */
  652. void IN_StartupJoystick (void)
  653. {
  654. int i, numdevs;
  655. JOYCAPS jc;
  656. MMRESULT mmr;
  657. // assume no joystick
  658. joy_avail = false;
  659. // abort startup if user requests no joystick
  660. if ( COM_CheckParm ("-nojoy") )
  661. return;
  662. // verify joystick driver is present
  663. if ((numdevs = joyGetNumDevs ()) == 0)
  664. {
  665. Con_Printf ("\njoystick not found -- driver not present\n\n");
  666. return;
  667. }
  668. // cycle through the joystick ids for the first valid one
  669. for (joy_id=0 ; joy_id<numdevs ; joy_id++)
  670. {
  671. memset (&ji, 0, sizeof(ji));
  672. ji.dwSize = sizeof(ji);
  673. ji.dwFlags = JOY_RETURNCENTERED;
  674. if ((mmr = joyGetPosEx (joy_id, &ji)) == JOYERR_NOERROR)
  675. break;
  676. }
  677. // abort startup if we didn't find a valid joystick
  678. if (mmr != JOYERR_NOERROR)
  679. {
  680. Con_Printf ("\njoystick not found -- no valid joysticks (%x)\n\n", mmr);
  681. return;
  682. }
  683. // get the capabilities of the selected joystick
  684. // abort startup if command fails
  685. memset (&jc, 0, sizeof(jc));
  686. if ((mmr = joyGetDevCaps (joy_id, &jc, sizeof(jc))) != JOYERR_NOERROR)
  687. {
  688. Con_Printf ("\njoystick not found -- invalid joystick capabilities (%x)\n\n", mmr);
  689. return;
  690. }
  691. // save the joystick's number of buttons and POV status
  692. joy_numbuttons = jc.wNumButtons;
  693. joy_haspov = jc.wCaps & JOYCAPS_HASPOV;
  694. // old button and POV states default to no buttons pressed
  695. joy_oldbuttonstate = joy_oldpovstate = 0;
  696. // mark the joystick as available and advanced initialization not completed
  697. // this is needed as cvars are not available during initialization
  698. joy_avail = true;
  699. joy_advancedinit = false;
  700. Con_Printf ("\njoystick detected\n\n");
  701. }
  702. /*
  703. ===========
  704. RawValuePointer
  705. ===========
  706. */
  707. PDWORD RawValuePointer (int axis)
  708. {
  709. switch (axis)
  710. {
  711. case JOY_AXIS_X:
  712. return &ji.dwXpos;
  713. case JOY_AXIS_Y:
  714. return &ji.dwYpos;
  715. case JOY_AXIS_Z:
  716. return &ji.dwZpos;
  717. case JOY_AXIS_R:
  718. return &ji.dwRpos;
  719. case JOY_AXIS_U:
  720. return &ji.dwUpos;
  721. case JOY_AXIS_V:
  722. return &ji.dwVpos;
  723. }
  724. }
  725. /*
  726. ===========
  727. Joy_AdvancedUpdate_f
  728. ===========
  729. */
  730. void Joy_AdvancedUpdate_f (void)
  731. {
  732. // called once by IN_ReadJoystick and by user whenever an update is needed
  733. // cvars are now available
  734. int i;
  735. DWORD dwTemp;
  736. // initialize all the maps
  737. for (i = 0; i < JOY_MAX_AXES; i++)
  738. {
  739. dwAxisMap[i] = AxisNada;
  740. dwControlMap[i] = JOY_ABSOLUTE_AXIS;
  741. pdwRawValue[i] = RawValuePointer(i);
  742. }
  743. if( joy_advanced.value == 0.0)
  744. {
  745. // default joystick initialization
  746. // 2 axes only with joystick control
  747. dwAxisMap[JOY_AXIS_X] = AxisTurn;
  748. // dwControlMap[JOY_AXIS_X] = JOY_ABSOLUTE_AXIS;
  749. dwAxisMap[JOY_AXIS_Y] = AxisForward;
  750. // dwControlMap[JOY_AXIS_Y] = JOY_ABSOLUTE_AXIS;
  751. }
  752. else
  753. {
  754. if (Q_strcmp (joy_name.string, "joystick") != 0)
  755. {
  756. // notify user of advanced controller
  757. Con_Printf ("\n%s configured\n\n", joy_name.string);
  758. }
  759. // advanced initialization here
  760. // data supplied by user via joy_axisn cvars
  761. dwTemp = (DWORD) joy_advaxisx.value;
  762. dwAxisMap[JOY_AXIS_X] = dwTemp & 0x0000000f;
  763. dwControlMap[JOY_AXIS_X] = dwTemp & JOY_RELATIVE_AXIS;
  764. dwTemp = (DWORD) joy_advaxisy.value;
  765. dwAxisMap[JOY_AXIS_Y] = dwTemp & 0x0000000f;
  766. dwControlMap[JOY_AXIS_Y] = dwTemp & JOY_RELATIVE_AXIS;
  767. dwTemp = (DWORD) joy_advaxisz.value;
  768. dwAxisMap[JOY_AXIS_Z] = dwTemp & 0x0000000f;
  769. dwControlMap[JOY_AXIS_Z] = dwTemp & JOY_RELATIVE_AXIS;
  770. dwTemp = (DWORD) joy_advaxisr.value;
  771. dwAxisMap[JOY_AXIS_R] = dwTemp & 0x0000000f;
  772. dwControlMap[JOY_AXIS_R] = dwTemp & JOY_RELATIVE_AXIS;
  773. dwTemp = (DWORD) joy_advaxisu.value;
  774. dwAxisMap[JOY_AXIS_U] = dwTemp & 0x0000000f;
  775. dwControlMap[JOY_AXIS_U] = dwTemp & JOY_RELATIVE_AXIS;
  776. dwTemp = (DWORD) joy_advaxisv.value;
  777. dwAxisMap[JOY_AXIS_V] = dwTemp & 0x0000000f;
  778. dwControlMap[JOY_AXIS_V] = dwTemp & JOY_RELATIVE_AXIS;
  779. }
  780. // compute the axes to collect from DirectInput
  781. joy_flags = JOY_RETURNCENTERED | JOY_RETURNBUTTONS | JOY_RETURNPOV;
  782. for (i = 0; i < JOY_MAX_AXES; i++)
  783. {
  784. if (dwAxisMap[i] != AxisNada)
  785. {
  786. joy_flags |= dwAxisFlags[i];
  787. }
  788. }
  789. }
  790. /*
  791. ===========
  792. IN_Commands
  793. ===========
  794. */
  795. void IN_Commands (void)
  796. {
  797. int i, key_index;
  798. DWORD buttonstate, povstate;
  799. if (!joy_avail)
  800. {
  801. return;
  802. }
  803. // loop through the joystick buttons
  804. // key a joystick event or auxillary event for higher number buttons for each state change
  805. buttonstate = ji.dwButtons;
  806. for (i=0 ; i < joy_numbuttons ; i++)
  807. {
  808. if ( (buttonstate & (1<<i)) && !(joy_oldbuttonstate & (1<<i)) )
  809. {
  810. key_index = (i < 4) ? K_JOY1 : K_AUX1;
  811. Key_Event (key_index + i, true);
  812. }
  813. if ( !(buttonstate & (1<<i)) && (joy_oldbuttonstate & (1<<i)) )
  814. {
  815. key_index = (i < 4) ? K_JOY1 : K_AUX1;
  816. Key_Event (key_index + i, false);
  817. }
  818. }
  819. joy_oldbuttonstate = buttonstate;
  820. if (joy_haspov)
  821. {
  822. // convert POV information into 4 bits of state information
  823. // this avoids any potential problems related to moving from one
  824. // direction to another without going through the center position
  825. povstate = 0;
  826. if(ji.dwPOV != JOY_POVCENTERED)
  827. {
  828. if (ji.dwPOV == JOY_POVFORWARD)
  829. povstate |= 0x01;
  830. if (ji.dwPOV == JOY_POVRIGHT)
  831. povstate |= 0x02;
  832. if (ji.dwPOV == JOY_POVBACKWARD)
  833. povstate |= 0x04;
  834. if (ji.dwPOV == JOY_POVLEFT)
  835. povstate |= 0x08;
  836. }
  837. // determine which bits have changed and key an auxillary event for each change
  838. for (i=0 ; i < 4 ; i++)
  839. {
  840. if ( (povstate & (1<<i)) && !(joy_oldpovstate & (1<<i)) )
  841. {
  842. Key_Event (K_AUX29 + i, true);
  843. }
  844. if ( !(povstate & (1<<i)) && (joy_oldpovstate & (1<<i)) )
  845. {
  846. Key_Event (K_AUX29 + i, false);
  847. }
  848. }
  849. joy_oldpovstate = povstate;
  850. }
  851. }
  852. /*
  853. ===============
  854. IN_ReadJoystick
  855. ===============
  856. */
  857. qboolean IN_ReadJoystick (void)
  858. {
  859. memset (&ji, 0, sizeof(ji));
  860. ji.dwSize = sizeof(ji);
  861. ji.dwFlags = joy_flags;
  862. if (joyGetPosEx (joy_id, &ji) == JOYERR_NOERROR)
  863. {
  864. // this is a hack -- there is a bug in the Logitech WingMan Warrior DirectInput Driver
  865. // rather than having 32768 be the zero point, they have the zero point at 32668
  866. // go figure -- anyway, now we get the full resolution out of the device
  867. if (joy_wwhack1.value != 0.0)
  868. {
  869. ji.dwUpos += 100;
  870. }
  871. return true;
  872. }
  873. else
  874. {
  875. // read error occurred
  876. // turning off the joystick seems too harsh for 1 read error,\
  877. // but what should be done?
  878. // Con_Printf ("IN_ReadJoystick: no response\n");
  879. // joy_avail = false;
  880. return false;
  881. }
  882. }
  883. /*
  884. ===========
  885. IN_JoyMove
  886. ===========
  887. */
  888. void IN_JoyMove (usercmd_t *cmd)
  889. {
  890. float speed, aspeed;
  891. float fAxisValue, fTemp;
  892. int i;
  893. // complete initialization if first time in
  894. // this is needed as cvars are not available at initialization time
  895. if( joy_advancedinit != true )
  896. {
  897. Joy_AdvancedUpdate_f();
  898. joy_advancedinit = true;
  899. }
  900. // verify joystick is available and that the user wants to use it
  901. if (!joy_avail || !in_joystick.value)
  902. {
  903. return;
  904. }
  905. // collect the joystick data, if possible
  906. if (IN_ReadJoystick () != true)
  907. {
  908. return;
  909. }
  910. if (in_speed.state & 1)
  911. speed = cl_movespeedkey.value;
  912. else
  913. speed = 1;
  914. aspeed = speed * host_frametime;
  915. // loop through the axes
  916. for (i = 0; i < JOY_MAX_AXES; i++)
  917. {
  918. // get the floating point zero-centered, potentially-inverted data for the current axis
  919. fAxisValue = (float) *pdwRawValue[i];
  920. // move centerpoint to zero
  921. fAxisValue -= 32768.0;
  922. if (joy_wwhack2.value != 0.0)
  923. {
  924. if (dwAxisMap[i] == AxisTurn)
  925. {
  926. // this is a special formula for the Logitech WingMan Warrior
  927. // y=ax^b; where a = 300 and b = 1.3
  928. // also x values are in increments of 800 (so this is factored out)
  929. // then bounds check result to level out excessively high spin rates
  930. fTemp = 300.0 * pow(abs(fAxisValue) / 800.0, 1.3);
  931. if (fTemp > 14000.0)
  932. fTemp = 14000.0;
  933. // restore direction information
  934. fAxisValue = (fAxisValue > 0.0) ? fTemp : -fTemp;
  935. }
  936. }
  937. // convert range from -32768..32767 to -1..1
  938. fAxisValue /= 32768.0;
  939. switch (dwAxisMap[i])
  940. {
  941. case AxisForward:
  942. if ((joy_advanced.value == 0.0) && (in_mlook.state & 1))
  943. {
  944. // user wants forward control to become look control
  945. if (fabs(fAxisValue) > joy_pitchthreshold.value)
  946. {
  947. // if mouse invert is on, invert the joystick pitch value
  948. // only absolute control support here (joy_advanced is false)
  949. if (m_pitch.value < 0.0)
  950. {
  951. cl.viewangles[PITCH] -= (fAxisValue * joy_pitchsensitivity.value) * aspeed * cl_pitchspeed.value;
  952. }
  953. else
  954. {
  955. cl.viewangles[PITCH] += (fAxisValue * joy_pitchsensitivity.value) * aspeed * cl_pitchspeed.value;
  956. }
  957. V_StopPitchDrift();
  958. }
  959. else
  960. {
  961. // no pitch movement
  962. // disable pitch return-to-center unless requested by user
  963. // *** this code can be removed when the lookspring bug is fixed
  964. // *** the bug always has the lookspring feature on
  965. if(lookspring.value == 0.0)
  966. V_StopPitchDrift();
  967. }
  968. }
  969. else
  970. {
  971. // user wants forward control to be forward control
  972. if (fabs(fAxisValue) > joy_forwardthreshold.value)
  973. {
  974. cmd->forwardmove += (fAxisValue * joy_forwardsensitivity.value) * speed * cl_forwardspeed.value;
  975. }
  976. }
  977. break;
  978. case AxisSide:
  979. if (fabs(fAxisValue) > joy_sidethreshold.value)
  980. {
  981. cmd->sidemove += (fAxisValue * joy_sidesensitivity.value) * speed * cl_sidespeed.value;
  982. }
  983. break;
  984. case AxisTurn:
  985. if ((in_strafe.state & 1) || (lookstrafe.value && (in_mlook.state & 1)))
  986. {
  987. // user wants turn control to become side control
  988. if (fabs(fAxisValue) > joy_sidethreshold.value)
  989. {
  990. cmd->sidemove -= (fAxisValue * joy_sidesensitivity.value) * speed * cl_sidespeed.value;
  991. }
  992. }
  993. else
  994. {
  995. // user wants turn control to be turn control
  996. if (fabs(fAxisValue) > joy_yawthreshold.value)
  997. {
  998. if(dwControlMap[i] == JOY_ABSOLUTE_AXIS)
  999. {
  1000. cl.viewangles[YAW] += (fAxisValue * joy_yawsensitivity.value) * aspeed * cl_yawspeed.value;
  1001. }
  1002. else
  1003. {
  1004. cl.viewangles[YAW] += (fAxisValue * joy_yawsensitivity.value) * speed * 180.0;
  1005. }
  1006. }
  1007. }
  1008. break;
  1009. case AxisLook:
  1010. if (in_mlook.state & 1)
  1011. {
  1012. if (fabs(fAxisValue) > joy_pitchthreshold.value)
  1013. {
  1014. // pitch movement detected and pitch movement desired by user
  1015. if(dwControlMap[i] == JOY_ABSOLUTE_AXIS)
  1016. {
  1017. cl.viewangles[PITCH] += (fAxisValue * joy_pitchsensitivity.value) * aspeed * cl_pitchspeed.value;
  1018. }
  1019. else
  1020. {
  1021. cl.viewangles[PITCH] += (fAxisValue * joy_pitchsensitivity.value) * speed * 180.0;
  1022. }
  1023. V_StopPitchDrift();
  1024. }
  1025. else
  1026. {
  1027. // no pitch movement
  1028. // disable pitch return-to-center unless requested by user
  1029. // *** this code can be removed when the lookspring bug is fixed
  1030. // *** the bug always has the lookspring feature on
  1031. if(lookspring.value == 0.0)
  1032. V_StopPitchDrift();
  1033. }
  1034. }
  1035. break;
  1036. default:
  1037. break;
  1038. }
  1039. }
  1040. // bounds check pitch
  1041. if (cl.viewangles[PITCH] > 80.0)
  1042. cl.viewangles[PITCH] = 80.0;
  1043. if (cl.viewangles[PITCH] < -70.0)
  1044. cl.viewangles[PITCH] = -70.0;
  1045. }