home *** CD-ROM | disk | FTP | other *** search
/ Magazyn Amiga 14 / MA_Cover_14.iso / source / c / q1source_amy / qw / client / in_win.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-12-21  |  27.7 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.