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