Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  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 (&current_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 (&current_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. {
  799.         int                     i, numdevs;
  800.         JOYCAPS         jc;
  801.         MMRESULT        mmr;
  802.  
  803.         // assume no joystick
  804.         joy_avail = false;
  805.  
  806.         // abort startup if user requests no joystick
  807.         if ( COM_CheckParm ("-nojoy") )
  808.                 return;
  809.  
  810.         // verify joystick driver is present
  811.         if ((numdevs = joyGetNumDevs ()) == 0)
  812.         {
  813.                 Con_Printf ("\njoystick not found -- driver not present\n\n");
  814.                 return;
  815.         }
  816.  
  817.         // cycle through the joystick ids for the first valid one
  818.         for (joy_id=0 ; joy_id<numdevs ; joy_id++)
  819.         {
  820.                 memset (&ji, 0, sizeof(ji));
  821.                 ji.dwSize = sizeof(ji);
  822.                 ji.dwFlags = JOY_RETURNCENTERED;
  823.  
  824.                 if ((mmr = joyGetPosEx (joy_id, &ji)) == JOYERR_NOERROR)
  825.                         break;
  826.         }
  827.  
  828.         // abort startup if we didn't find a valid joystick
  829.         if (mmr != JOYERR_NOERROR)
  830.         {
  831.                 Con_Printf ("\njoystick not found -- no valid joysticks (%x)\n\n", mmr);
  832.                 return;
  833.         }
  834.  
  835.         // get the capabilities of the selected joystick
  836.         // abort startup if command fails
  837.         memset (&jc, 0, sizeof(jc));
  838.         if ((mmr = joyGetDevCaps (joy_id, &jc, sizeof(jc))) != JOYERR_NOERROR)
  839.         {
  840.                 Con_Printf ("\njoystick not found -- invalid joystick capabilities (%x)\n\n", mmr);
  841.                 return;
  842.         }
  843.  
  844.         // save the joystick's number of buttons and POV status
  845.         joy_numbuttons = jc.wNumButtons;
  846.         joy_haspov = jc.wCaps & JOYCAPS_HASPOV;
  847.  
  848.         // old button and POV states default to no buttons pressed
  849.         joy_oldbuttonstate = joy_oldpovstate = 0;
  850.  
  851.         // mark the joystick as available and advanced initialization not completed
  852.         // this is needed as cvars are not available during initialization
  853.  
  854.         joy_avail = true;
  855.         joy_advancedinit = false;
  856.  
  857.         Con_Printf ("\njoystick detected\n\n");
  858. }
  859.  
  860.  
  861. /*
  862. ===========
  863. RawValuePointer
  864. ===========
  865. */
  866. PDWORD RawValuePointer (int axis)
  867. {
  868.         switch (axis)
  869.         {
  870.         case JOY_AXIS_X:
  871.                 return &ji.dwXpos;
  872.         case JOY_AXIS_Y:
  873.                 return &ji.dwYpos;
  874.         case JOY_AXIS_Z:
  875.                 return &ji.dwZpos;
  876.         case JOY_AXIS_R:
  877.                 return &ji.dwRpos;
  878.         case JOY_AXIS_U:
  879.                 return &ji.dwUpos;
  880.         case JOY_AXIS_V:
  881.                 return &ji.dwVpos;
  882.         }
  883. }
  884.  
  885.  
  886. /*
  887. ===========
  888. Joy_AdvancedUpdate_f
  889. ===========
  890. */
  891. void Joy_AdvancedUpdate_f (void)
  892. {
  893.  
  894.         // called once by IN_ReadJoystick and by user whenever an update is needed
  895.         // cvars are now available
  896.         int     i;
  897.         DWORD dwTemp;
  898.  
  899.         // initialize all the maps
  900.         for (i = 0; i < JOY_MAX_AXES; i++)
  901.         {
  902.                 dwAxisMap[i] = AxisNada;
  903.                 dwControlMap[i] = JOY_ABSOLUTE_AXIS;
  904.                 pdwRawValue[i] = RawValuePointer(i);
  905.         }
  906.  
  907.         if( joy_advanced.value == 0.0)
  908.         {
  909.                 // default joystick initialization
  910.                 // 2 axes only with joystick control
  911.                 dwAxisMap[JOY_AXIS_X] = AxisTurn;
  912.                 // dwControlMap[JOY_AXIS_X] = JOY_ABSOLUTE_AXIS;
  913.                 dwAxisMap[JOY_AXIS_Y] = AxisForward;
  914.                 // dwControlMap[JOY_AXIS_Y] = JOY_ABSOLUTE_AXIS;
  915.         }
  916.         else
  917.         {
  918.                 if (Q_strcmp (joy_name.string, "joystick") != 0)
  919.                 {
  920.                         // notify user of advanced controller
  921.                         Con_Printf ("\n%s configured\n\n", joy_name.string);
  922.                 }
  923.  
  924.                 // advanced initialization here
  925.                 // data supplied by user via joy_axisn cvars
  926.                 dwTemp = (DWORD) joy_advaxisx.value;
  927.                 dwAxisMap[JOY_AXIS_X] = dwTemp & 0x0000000f;
  928.                 dwControlMap[JOY_AXIS_X] = dwTemp & JOY_RELATIVE_AXIS;
  929.                 dwTemp = (DWORD) joy_advaxisy.value;
  930.                 dwAxisMap[JOY_AXIS_Y] = dwTemp & 0x0000000f;
  931.                 dwControlMap[JOY_AXIS_Y] = dwTemp & JOY_RELATIVE_AXIS;
  932.                 dwTemp = (DWORD) joy_advaxisz.value;
  933.                 dwAxisMap[JOY_AXIS_Z] = dwTemp & 0x0000000f;
  934.                 dwControlMap[JOY_AXIS_Z] = dwTemp & JOY_RELATIVE_AXIS;
  935.                 dwTemp = (DWORD) joy_advaxisr.value;
  936.                 dwAxisMap[JOY_AXIS_R] = dwTemp & 0x0000000f;
  937.                 dwControlMap[JOY_AXIS_R] = dwTemp & JOY_RELATIVE_AXIS;
  938.                 dwTemp = (DWORD) joy_advaxisu.value;
  939.                 dwAxisMap[JOY_AXIS_U] = dwTemp & 0x0000000f;
  940.                 dwControlMap[JOY_AXIS_U] = dwTemp & JOY_RELATIVE_AXIS;
  941.                 dwTemp = (DWORD) joy_advaxisv.value;
  942.                 dwAxisMap[JOY_AXIS_V] = dwTemp & 0x0000000f;
  943.                 dwControlMap[JOY_AXIS_V] = dwTemp & JOY_RELATIVE_AXIS;
  944.         }
  945.  
  946.         // compute the axes to collect from DirectInput
  947.         joy_flags = JOY_RETURNCENTERED | JOY_RETURNBUTTONS | JOY_RETURNPOV;
  948.         for (i = 0; i < JOY_MAX_AXES; i++)
  949.         {
  950.                 if (dwAxisMap[i] != AxisNada)
  951.                 {
  952.                         joy_flags |= dwAxisFlags[i];
  953.                 }
  954.         }
  955. }
  956.  
  957.  
  958. /*
  959. ===========
  960. IN_Commands
  961. ===========
  962. */
  963. void IN_Commands (void)
  964. {
  965.         int             i, key_index;
  966.         DWORD   buttonstate, povstate;
  967.  
  968.         if (!joy_avail)
  969.         {
  970.                 return;
  971.         }
  972.  
  973.        
  974.         // loop through the joystick buttons
  975.         // key a joystick event or auxillary event for higher number buttons for each state change
  976.         buttonstate = ji.dwButtons;
  977.         for (i=0 ; i < joy_numbuttons ; i++)
  978.         {
  979.                 if ( (buttonstate & (1<<i)) && !(joy_oldbuttonstate & (1<<i)) )
  980.                 {
  981.                         key_index = (i < 4) ? K_JOY1 : K_AUX1;
  982.                         Key_Event (key_index + i, true);
  983.                 }
  984.  
  985.                 if ( !(buttonstate & (1<<i)) && (joy_oldbuttonstate & (1<<i)) )
  986.                 {
  987.                         key_index = (i < 4) ? K_JOY1 : K_AUX1;
  988.                         Key_Event (key_index + i, false);
  989.                 }
  990.         }
  991.         joy_oldbuttonstate = buttonstate;
  992.  
  993.         if (joy_haspov)
  994.         {
  995.                 // convert POV information into 4 bits of state information
  996.                 // this avoids any potential problems related to moving from one
  997.                 // direction to another without going through the center position
  998.                 povstate = 0;
  999.                 if(ji.dwPOV != JOY_POVCENTERED)
  1000.                 {
  1001.                         if (ji.dwPOV == JOY_POVFORWARD)
  1002.                                 povstate |= 0x01;
  1003.                         if (ji.dwPOV == JOY_POVRIGHT)
  1004.                                 povstate |= 0x02;
  1005.                         if (ji.dwPOV == JOY_POVBACKWARD)
  1006.                                 povstate |= 0x04;
  1007.                         if (ji.dwPOV == JOY_POVLEFT)
  1008.                                 povstate |= 0x08;
  1009.                 }
  1010.                 // determine which bits have changed and key an auxillary event for each change
  1011.                 for (i=0 ; i < 4 ; i++)
  1012.                 {
  1013.                         if ( (povstate & (1<<i)) && !(joy_oldpovstate & (1<<i)) )
  1014.                         {
  1015.                                 Key_Event (K_AUX29 + i, true);
  1016.                         }
  1017.  
  1018.                         if ( !(povstate & (1<<i)) && (joy_oldpovstate & (1<<i)) )
  1019.                         {
  1020.                                 Key_Event (K_AUX29 + i, false);
  1021.                         }
  1022.                 }
  1023.                 joy_oldpovstate = povstate;
  1024.         }
  1025. }
  1026.  
  1027.  
  1028. /*
  1029. ===============
  1030. IN_ReadJoystick
  1031. ===============
  1032. */  
  1033. qboolean IN_ReadJoystick (void)
  1034. {
  1035.  
  1036.         memset (&ji, 0, sizeof(ji));
  1037.         ji.dwSize = sizeof(ji);
  1038.         ji.dwFlags = joy_flags;
  1039.  
  1040.         if (joyGetPosEx (joy_id, &ji) == JOYERR_NOERROR)
  1041.         {
  1042.                 // this is a hack -- there is a bug in the Logitech WingMan Warrior DirectInput Driver
  1043.                 // rather than having 32768 be the zero point, they have the zero point at 32668
  1044.                 // go figure -- anyway, now we get the full resolution out of the device
  1045.                 if (joy_wwhack1.value != 0.0)
  1046.                 {
  1047.                         ji.dwUpos += 100;
  1048.                 }
  1049.                 return true;
  1050.         }
  1051.         else
  1052.         {
  1053.                 // read error occurred
  1054.                 // turning off the joystick seems too harsh for 1 read error,\
  1055.                 // but what should be done?
  1056.                 // Con_Printf ("IN_ReadJoystick: no response\n");
  1057.                 // joy_avail = false;
  1058.                 return false;
  1059.         }
  1060. }
  1061.  
  1062.  
  1063. /*
  1064. ===========
  1065. IN_JoyMove
  1066. ===========
  1067. */
  1068. void IN_JoyMove (usercmd_t *cmd)
  1069. {
  1070.         float   speed, aspeed;
  1071.         float   fAxisValue, fTemp;
  1072.         int             i;
  1073.  
  1074.         // complete initialization if first time in
  1075.         // this is needed as cvars are not available at initialization time
  1076.         if( joy_advancedinit != true )
  1077.         {
  1078.                 Joy_AdvancedUpdate_f();
  1079.                 joy_advancedinit = true;
  1080.         }
  1081.  
  1082.         // verify joystick is available and that the user wants to use it
  1083.         if (!joy_avail || !in_joystick.value)
  1084.         {
  1085.                 return;
  1086.         }
  1087.  
  1088.         // collect the joystick data, if possible
  1089.         if (IN_ReadJoystick () != true)
  1090.         {
  1091.                 return;
  1092.         }
  1093.  
  1094.         if (in_speed.state & 1)
  1095.                 speed = cl_movespeedkey.value;
  1096.         else
  1097.                 speed = 1;
  1098.         aspeed = speed * host_frametime;
  1099.  
  1100.         // loop through the axes
  1101.         for (i = 0; i < JOY_MAX_AXES; i++)
  1102.         {
  1103.                 // get the floating point zero-centered, potentially-inverted data for the current axis
  1104.                 fAxisValue = (float) *pdwRawValue[i];
  1105.                 // move centerpoint to zero
  1106.                 fAxisValue -= 32768.0;
  1107.  
  1108.                 if (joy_wwhack2.value != 0.0)
  1109.                 {
  1110.                         if (dwAxisMap[i] == AxisTurn)
  1111.                         {
  1112.                                 // this is a special formula for the Logitech WingMan Warrior
  1113.                                 // y=ax^b; where a = 300 and b = 1.3
  1114.                                 // also x values are in increments of 800 (so this is factored out)
  1115.                                 // then bounds check result to level out excessively high spin rates
  1116.                                 fTemp = 300.0 * pow(abs(fAxisValue) / 800.0, 1.3);
  1117.                                 if (fTemp > 14000.0)
  1118.                                         fTemp = 14000.0;
  1119.                                 // restore direction information
  1120.                                 fAxisValue = (fAxisValue > 0.0) ? fTemp : -fTemp;
  1121.                         }
  1122.                 }
  1123.  
  1124.                 // convert range from -32768..32767 to -1..1
  1125.                 fAxisValue /= 32768.0;
  1126.  
  1127.                 switch (dwAxisMap[i])
  1128.                 {
  1129.                 case AxisForward:
  1130.                         if ((joy_advanced.value == 0.0) && (in_mlook.state & 1))
  1131.                         {
  1132.                                 // user wants forward control to become look control
  1133.                                 if (fabs(fAxisValue) > joy_pitchthreshold.value)
  1134.                                 {              
  1135.                                         // if mouse invert is on, invert the joystick pitch value
  1136.                                         // only absolute control support here (joy_advanced is false)
  1137.                                         if (m_pitch.value < 0.0)
  1138.                                         {
  1139.                                                 cl.viewangles[PITCH] -= (fAxisValue * joy_pitchsensitivity.value) * aspeed * cl_pitchspeed.value;
  1140.                                         }
  1141.                                         else
  1142.                                         {
  1143.                                                 cl.viewangles[PITCH] += (fAxisValue * joy_pitchsensitivity.value) * aspeed * cl_pitchspeed.value;
  1144.                                         }
  1145.                                         V_StopPitchDrift();
  1146.                                 }
  1147.                                 else
  1148.                                 {
  1149.                                         // no pitch movement
  1150.                                         // disable pitch return-to-center unless requested by user
  1151.                                         // *** this code can be removed when the lookspring bug is fixed
  1152.                                         // *** the bug always has the lookspring feature on
  1153.                                         if(lookspring.value == 0.0)
  1154.                                                 V_StopPitchDrift();
  1155.                                 }
  1156.                         }
  1157.                         else
  1158.                         {
  1159.                                 // user wants forward control to be forward control
  1160.                                 if (fabs(fAxisValue) > joy_forwardthreshold.value)
  1161.                                 {
  1162.                                         cmd->forwardmove += (fAxisValue * joy_forwardsensitivity.value) * speed * cl_forwardspeed.value;
  1163.                                 }
  1164.                         }
  1165.                         break;
  1166.  
  1167.                 case AxisSide:
  1168.                         if (fabs(fAxisValue) > joy_sidethreshold.value)
  1169.                         {
  1170.                                 cmd->sidemove += (fAxisValue * joy_sidesensitivity.value) * speed * cl_sidespeed.value;
  1171.                         }
  1172.                         break;
  1173.  
  1174.                 case AxisTurn:
  1175.                         if ((in_strafe.state & 1) || (lookstrafe.value && (in_mlook.state & 1)))
  1176.                         {
  1177.                                 // user wants turn control to become side control
  1178.                                 if (fabs(fAxisValue) > joy_sidethreshold.value)
  1179.                                 {
  1180.                                         cmd->sidemove -= (fAxisValue * joy_sidesensitivity.value) * speed * cl_sidespeed.value;
  1181.                                 }
  1182.                         }
  1183.                         else
  1184.                         {
  1185.                                 // user wants turn control to be turn control
  1186.                                 if (fabs(fAxisValue) > joy_yawthreshold.value)
  1187.                                 {
  1188.                                         if(dwControlMap[i] == JOY_ABSOLUTE_AXIS)
  1189.                                         {
  1190.                                                 cl.viewangles[YAW] += (fAxisValue * joy_yawsensitivity.value) * aspeed * cl_yawspeed.value;
  1191.                                         }
  1192.                                         else
  1193.                                         {
  1194.                                                 cl.viewangles[YAW] += (fAxisValue * joy_yawsensitivity.value) * speed * 180.0;
  1195.                                         }
  1196.  
  1197.                                 }
  1198.                         }
  1199.                         break;
  1200.  
  1201.                 case AxisLook:
  1202.                         if (in_mlook.state & 1)
  1203.                         {
  1204.                                 if (fabs(fAxisValue) > joy_pitchthreshold.value)
  1205.                                 {
  1206.                                         // pitch movement detected and pitch movement desired by user
  1207.                                         if(dwControlMap[i] == JOY_ABSOLUTE_AXIS)
  1208.                                         {
  1209.                                                 cl.viewangles[PITCH] += (fAxisValue * joy_pitchsensitivity.value) * aspeed * cl_pitchspeed.value;
  1210.                                         }
  1211.                                         else
  1212.                                         {
  1213.                                                 cl.viewangles[PITCH] += (fAxisValue * joy_pitchsensitivity.value) * speed * 180.0;
  1214.                                         }
  1215.                                         V_StopPitchDrift();
  1216.                                 }
  1217.                                 else
  1218.                                 {
  1219.                                         // no pitch movement
  1220.                                         // disable pitch return-to-center unless requested by user
  1221.                                         // *** this code can be removed when the lookspring bug is fixed
  1222.                                         // *** the bug always has the lookspring feature on
  1223.                                         if(lookspring.value == 0.0)
  1224.                                                 V_StopPitchDrift();
  1225.                                 }
  1226.                         }
  1227.                         break;
  1228.  
  1229.                 default:
  1230.                         break;
  1231.                 }
  1232.         }
  1233.  
  1234.         // bounds check pitch
  1235.         if (cl.viewangles[PITCH] > 80.0)
  1236.                 cl.viewangles[PITCH] = 80.0;
  1237.         if (cl.viewangles[PITCH] < -70.0)
  1238.                 cl.viewangles[PITCH] = -70.0;
  1239. }
  1240.