home *** CD-ROM | disk | FTP | other *** search
/ Enigma Amiga Life 113 / EnigmaAmiga113CD.iso / software / sviluppo / quake_src / in_win.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-06-17  |  28.4 KB  |  1,240 lines

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