// in_win.c -- windows 95 mouse and joystick code // 02/21/97 JCB Added extended DirectInput code to support external controllers. /* * $Header: /H2 Mission Pack/IN_WIN.C 3 3/01/98 8:20p Jmonroe $ */ #include "quakedef.h" #include "winquake.h" #include "dosisms.h" // mouse variables cvar_t m_filter = {"m_filter","0"}; int mouse_buttons; int mouse_oldbuttonstate; POINT current_pos; int mouse_x, mouse_y, old_mouse_x, old_mouse_y, mx_accum, my_accum; static qboolean restore_spi; static int originalmouseparms[3], newmouseparms[3] = {0, 0, 1}; static qboolean mouseactive; qboolean mouseinitialized; static qboolean mouseparmsvalid, mouseactivatetoggle; static qboolean mouseshowtoggle = 1; // joystick defines and variables // where should defines be moved? #define JOY_ABSOLUTE_AXIS 0x00000000 // control like a joystick #define JOY_RELATIVE_AXIS 0x00000010 // control like a mouse, spinner, trackball #define JOY_MAX_AXES 6 // X, Y, Z, R, U, V #define JOY_AXIS_X 0 #define JOY_AXIS_Y 1 #define JOY_AXIS_Z 2 #define JOY_AXIS_R 3 #define JOY_AXIS_U 4 #define JOY_AXIS_V 5 enum _ControlList { AxisNada = 0, AxisForward, AxisLook, AxisSide, AxisTurn }; DWORD dwAxisFlags[JOY_MAX_AXES] = { JOY_RETURNX, JOY_RETURNY, JOY_RETURNZ, JOY_RETURNR, JOY_RETURNU, JOY_RETURNV }; DWORD dwAxisMap[JOY_MAX_AXES]; DWORD dwControlMap[JOY_MAX_AXES]; PDWORD pdwRawValue[JOY_MAX_AXES]; // none of these cvars are saved over a session // this means that advanced controller configuration needs to be executed // each time. this avoids any problems with getting back to a default usage // or when changing from one controller to another. this way at least something // works. cvar_t in_joystick = {"joystick","1"}; cvar_t joy_name = {"joyname", "joystick"}; cvar_t joy_advanced = {"joyadvanced", "0"}; cvar_t joy_advaxisx = {"joyadvaxisx", "0"}; cvar_t joy_advaxisy = {"joyadvaxisy", "0"}; cvar_t joy_advaxisz = {"joyadvaxisz", "0"}; cvar_t joy_advaxisr = {"joyadvaxisr", "0"}; cvar_t joy_advaxisu = {"joyadvaxisu", "0"}; cvar_t joy_advaxisv = {"joyadvaxisv", "0"}; cvar_t joy_forwardthreshold = {"joyforwardthreshold", "0.15"}; cvar_t joy_sidethreshold = {"joysidethreshold", "0.15"}; cvar_t joy_pitchthreshold = {"joypitchthreshold", "0.15"}; cvar_t joy_yawthreshold = {"joyyawthreshold", "0.15"}; cvar_t joy_forwardsensitivity = {"joyforwardsensitivity", "-1.0"}; cvar_t joy_sidesensitivity = {"joysidesensitivity", "-1.0"}; cvar_t joy_pitchsensitivity = {"joypitchsensitivity", "1.0"}; cvar_t joy_yawsensitivity = {"joyyawsensitivity", "-1.0"}; cvar_t joy_wwhack1 = {"joywwhack1", "0.0"}; cvar_t joy_wwhack2 = {"joywwhack2", "0.0"}; qboolean joy_avail, joy_advancedinit, joy_haspov; DWORD joy_oldbuttonstate, joy_oldpovstate; int joy_id; DWORD joy_flags; DWORD joy_numbuttons; static JOYINFOEX ji; // forward-referenced functions void IN_StartupJoystick (void); void Joy_AdvancedUpdate_f (void); void IN_JoyMove (usercmd_t *cmd); /* =========== Force_CenterView_f =========== */ void Force_CenterView_f (void) { cl.viewangles[PITCH] = 0; } /* =========== IN_UpdateClipCursor =========== */ void IN_UpdateClipCursor (void) { if (mouseinitialized && mouseactive) ClipCursor (&window_rect); } /* =========== IN_ShowMouse =========== */ void IN_ShowMouse (void) { if (!mouseshowtoggle) { ShowCursor (TRUE); mouseshowtoggle = 1; } } /* =========== IN_HideMouse =========== */ void IN_HideMouse (void) { if (mouseshowtoggle) { ShowCursor (FALSE); mouseshowtoggle = 0; } } /* =========== IN_ActivateMouse =========== */ void IN_ActivateMouse (void) { mouseactivatetoggle = true; if (mouseinitialized) { if (mouseparmsvalid) restore_spi = SystemParametersInfo (SPI_SETMOUSE, 0, newmouseparms, 0); SetCursorPos (window_center_x, window_center_y); mouseactive = true; SetCapture (mainwindow); ClipCursor (&window_rect); } } /* =========== IN_SetQuakeMouseState =========== */ void IN_SetQuakeMouseState (void) { if (mouseactivatetoggle) IN_ActivateMouse (); } /* =========== IN_DeactivateMouse =========== */ void IN_DeactivateMouse (void) { mouseactivatetoggle = false; if (mouseinitialized) { if (restore_spi) SystemParametersInfo (SPI_SETMOUSE, 0, originalmouseparms, 0); mouseactive = false; ClipCursor (NULL); ReleaseCapture (); } } /* =========== IN_RestoreOriginalMouseState =========== */ void IN_RestoreOriginalMouseState (void) { if (mouseactivatetoggle) { IN_DeactivateMouse (); mouseactivatetoggle = true; } // try to redraw the cursor so it gets reinitialized, because sometimes it // has garbage after the mode switch ShowCursor (TRUE); ShowCursor (FALSE); } /* =========== IN_StartupMouse =========== */ void IN_StartupMouse (void) { HDC hdc; if ( COM_CheckParm ("-nomouse") ) return; mouseinitialized = true; mouseparmsvalid = SystemParametersInfo (SPI_GETMOUSE, 0, originalmouseparms, 0); if (mouseparmsvalid) { if ( COM_CheckParm ("-noforcemspd") ) newmouseparms[2] = originalmouseparms[2]; if ( COM_CheckParm ("-noforcemaccel") ) { newmouseparms[0] = originalmouseparms[0]; newmouseparms[1] = originalmouseparms[1]; } if ( COM_CheckParm ("-noforcemparms") ) { newmouseparms[0] = originalmouseparms[0]; newmouseparms[1] = originalmouseparms[1]; newmouseparms[2] = originalmouseparms[2]; } } mouse_buttons = 3; if (mouse_buttons > 3) mouse_buttons = 3; // if a fullscreen video mode was set before the mouse was initialized, // set the mouse state appropriately if (mouseactivatetoggle) IN_ActivateMouse (); } /* =========== IN_Init =========== */ void IN_Init (void) { // mouse variables Cvar_RegisterVariable (&m_filter); // joystick variables Cvar_RegisterVariable (&in_joystick); Cvar_RegisterVariable (&joy_name); Cvar_RegisterVariable (&joy_advanced); Cvar_RegisterVariable (&joy_advaxisx); Cvar_RegisterVariable (&joy_advaxisy); Cvar_RegisterVariable (&joy_advaxisz); Cvar_RegisterVariable (&joy_advaxisr); Cvar_RegisterVariable (&joy_advaxisu); Cvar_RegisterVariable (&joy_advaxisv); Cvar_RegisterVariable (&joy_forwardthreshold); Cvar_RegisterVariable (&joy_sidethreshold); Cvar_RegisterVariable (&joy_pitchthreshold); Cvar_RegisterVariable (&joy_yawthreshold); Cvar_RegisterVariable (&joy_forwardsensitivity); Cvar_RegisterVariable (&joy_sidesensitivity); Cvar_RegisterVariable (&joy_pitchsensitivity); Cvar_RegisterVariable (&joy_yawsensitivity); Cvar_RegisterVariable (&joy_wwhack1); Cvar_RegisterVariable (&joy_wwhack2); Cmd_AddCommand ("force_centerview", Force_CenterView_f); Cmd_AddCommand ("joyadvancedupdate", Joy_AdvancedUpdate_f); IN_StartupMouse (); IN_StartupJoystick (); } /* =========== IN_Shutdown =========== */ void IN_Shutdown (void) { IN_DeactivateMouse (); IN_ShowMouse (); } /* =========== IN_MouseEvent =========== */ void IN_MouseEvent (int mstate) { int i; if (mouseactive) { // perform button actions for (i=0 ; iv.cameramode) // Stuck in a different camera, don't move // return; GetCursorPos (¤t_pos); mx = current_pos.x - window_center_x + mx_accum; my = current_pos.y - window_center_y + my_accum; mx_accum = 0; my_accum = 0; if (m_filter.value) { mouse_x = (mx + old_mouse_x) * 0.5; mouse_y = (my + old_mouse_y) * 0.5; } else { mouse_x = mx; mouse_y = my; } old_mouse_x = mx; old_mouse_y = my; mouse_x *= sensitivity.value; mouse_y *= sensitivity.value; // add mouse X/Y movement to cmd if ( (in_strafe.state & 1) || (lookstrafe.value && (in_mlook.state & 1) )) cmd->sidemove += m_side.value * mouse_x; else cl.viewangles[YAW] -= m_yaw.value * mouse_x; if (in_mlook.state & 1) V_StopPitchDrift (); if ( (in_mlook.state & 1) && !(in_strafe.state & 1)) { cl.viewangles[PITCH] += m_pitch.value * mouse_y; if (cl.viewangles[PITCH] > 80) cl.viewangles[PITCH] = 80; if (cl.viewangles[PITCH] < -70) cl.viewangles[PITCH] = -70; } else { if ((in_strafe.state & 1) && noclip_anglehack) cmd->upmove -= m_forward.value * mouse_y; else cmd->forwardmove -= m_forward.value * mouse_y; } if (cl.idealroll == 0) // Did keyboard set it already?? { if ((mouse_x <0) && (cl.v.movetype==MOVETYPE_FLY)) cl.idealroll=-10; else if ((mouse_x >0) && (cl.v.movetype==MOVETYPE_FLY)) cl.idealroll=10; } // if the mouse has moved, force it to the center, so there's room to move if (mx || my) { SetCursorPos (window_center_x, window_center_y); } } /* =========== IN_Move =========== */ void IN_Move (usercmd_t *cmd) { if (cl.v.cameramode) // Stuck in a different camera so don't move { memset (cmd, 0, sizeof(*cmd)); return; } if (mouseactive) { IN_MouseMove (cmd); } if (ActiveApp) IN_JoyMove (cmd); } /* =========== IN_Accumulate =========== */ void IN_Accumulate (void) { int mx, my; HDC hdc; if (mouseactive) { GetCursorPos (¤t_pos); mx_accum += current_pos.x - window_center_x; my_accum += current_pos.y - window_center_y; // force the mouse to the center, so there's room to move SetCursorPos (window_center_x, window_center_y); } } /* =================== IN_ClearStates =================== */ void IN_ClearStates (void) { if (mouseactive) { mx_accum = 0; my_accum = 0; mouse_oldbuttonstate = 0; } } /* =============== IN_StartupJoystick =============== */ void IN_StartupJoystick (void) { int i, numdevs; JOYCAPS jc; MMRESULT mmr; // assume no joystick joy_avail = false; // abort startup if user requests no joystick if ( COM_CheckParm ("-nojoy") ) return; // verify joystick driver is present if ((numdevs = joyGetNumDevs ()) == 0) { Con_Printf ("\njoystick not found -- driver not present\n\n"); return; } // cycle through the joystick ids for the first valid one for (joy_id=0 ; joy_id 14000.0) fTemp = 14000.0; // restore direction information fAxisValue = (fAxisValue > 0.0) ? fTemp : -fTemp; } } // convert range from -32768..32767 to -1..1 fAxisValue /= 32768.0; switch (dwAxisMap[i]) { case AxisForward: if ((joy_advanced.value == 0.0) && (in_mlook.state & 1)) { // user wants forward control to become look control if (fastfabs(fAxisValue) > joy_pitchthreshold.value) { // if mouse invert is on, invert the joystick pitch value // only absolute control support here (joy_advanced is false) if (m_pitch.value < 0.0) { cl.viewangles[PITCH] -= (fAxisValue * joy_pitchsensitivity.value) * aspeed * cl_pitchspeed.value; } else { cl.viewangles[PITCH] += (fAxisValue * joy_pitchsensitivity.value) * aspeed * cl_pitchspeed.value; } V_StopPitchDrift(); } else { // no pitch movement // disable pitch return-to-center unless requested by user // *** this code can be removed when the lookspring bug is fixed // *** the bug always has the lookspring feature on if(lookspring.value == 0.0) V_StopPitchDrift(); } } else { // user wants forward control to be forward control if (fastfabs(fAxisValue) > joy_forwardthreshold.value) { // cmd->forwardmove += (fAxisValue * joy_forwardsensitivity.value) * speed * cl_forwardspeed.value; cmd->forwardmove += (fAxisValue * joy_forwardsensitivity.value) * speed * 200; } } break; case AxisSide: if (fastfabs(fAxisValue) > joy_sidethreshold.value) { // cmd->sidemove += (fAxisValue * joy_sidesensitivity.value) * speed * cl_sidespeed.value; cmd->sidemove += (fAxisValue * joy_sidesensitivity.value) * speed * 225; } break; case AxisTurn: if ((in_strafe.state & 1) || (lookstrafe.value && (in_mlook.state & 1))) { // user wants turn control to become side control if (fastfabs(fAxisValue) > joy_sidethreshold.value) { // cmd->sidemove -= (fAxisValue * joy_sidesensitivity.value) * speed * cl_sidespeed.value; cmd->sidemove -= (fAxisValue * joy_sidesensitivity.value) * speed * 225; } } else { // user wants turn control to be turn control if (fastfabs(fAxisValue) > joy_yawthreshold.value) { if(dwControlMap[i] == JOY_ABSOLUTE_AXIS) { cl.viewangles[YAW] += (fAxisValue * joy_yawsensitivity.value) * aspeed * cl_yawspeed.value; } else { cl.viewangles[YAW] += (fAxisValue * joy_yawsensitivity.value) * speed * 180.0; } } } break; case AxisLook: if (in_mlook.state & 1) { if (fastfabs(fAxisValue) > joy_pitchthreshold.value) { // pitch movement detected and pitch movement desired by user if(dwControlMap[i] == JOY_ABSOLUTE_AXIS) { cl.viewangles[PITCH] += (fAxisValue * joy_pitchsensitivity.value) * aspeed * cl_pitchspeed.value; } else { cl.viewangles[PITCH] += (fAxisValue * joy_pitchsensitivity.value) * speed * 180.0; } V_StopPitchDrift(); } else { // no pitch movement // disable pitch return-to-center unless requested by user // *** this code can be removed when the lookspring bug is fixed // *** the bug always has the lookspring feature on if(lookspring.value == 0.0) V_StopPitchDrift(); } } break; default: break; } } // bounds check pitch if (cl.viewangles[PITCH] > 80.0) cl.viewangles[PITCH] = 80.0; if (cl.viewangles[PITCH] < -70.0) cl.viewangles[PITCH] = -70.0; } /* * $Log: /H2 Mission Pack/IN_WIN.C $ * * 3 3/01/98 8:20p Jmonroe * removed the slow "quake" version of common functions * * 2 2/04/98 12:53a Jmonroe * added fastfabs * * 10 9/01/97 4:29a Rjohnson * Joystick fix * * 9 8/27/97 12:11p Rjohnson * Hardcoded speeds * * 8 8/26/97 11:38a Rlove * * 7 7/15/97 1:59p Rjohnson * Fix for mouse and client * * 6 3/25/97 11:28a Rlove * New camera entity * * 5 3/07/97 1:46p Rjohnson * Id Updates */