/* Copyright (C) 1997-2001 Id Software, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // in_win.c -- windows 95 mouse and joystick code // 02/21/97 JCB Added extended DirectInput code to support external controllers. #include "../client/client.h" #include "winquake.h" // wsw : pb #define DIRECTINPUT_VERSION 0x0300 #include #define DINPUT_BUFFERSIZE 32 //pb: try to use a bigger dinput buffer old 16 #define iDirectInputCreate(a,b,c,d) pDirectInputCreate(a,b,c,d) HRESULT (WINAPI *pDirectInputCreate)(HINSTANCE hinst, DWORD dwVersion, LPDIRECTINPUT * lplpDirectInput, LPUNKNOWN punkOuter); extern unsigned sys_msg_time; // 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, AxisUp }; 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]; cvar_t *in_mouse; cvar_t *in_grabinconsole; cvar_t *in_joystick; // 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 *joy_name; cvar_t *joy_advanced; cvar_t *joy_advaxisx; cvar_t *joy_advaxisy; cvar_t *joy_advaxisz; cvar_t *joy_advaxisr; cvar_t *joy_advaxisu; cvar_t *joy_advaxisv; cvar_t *joy_forwardthreshold; cvar_t *joy_sidethreshold; cvar_t *joy_pitchthreshold; cvar_t *joy_yawthreshold; cvar_t *joy_forwardsensitivity; cvar_t *joy_sidesensitivity; cvar_t *joy_pitchsensitivity; cvar_t *joy_yawsensitivity; cvar_t *joy_upthreshold; cvar_t *joy_upsensitivity; static qboolean jlooking = qfalse; qboolean joy_avail, joy_advancedinit, joy_haspov; DWORD joy_oldbuttonstate, joy_oldpovstate; int joy_id; DWORD joy_flags; DWORD joy_numbuttons; static JOYINFOEX ji; qboolean in_appactive; // forward-referenced functions void IN_StartupJoystick (void); void Joy_AdvancedUpdate_f (void); void IN_JoyMove (usercmd_t *cmd); /* ============================================================ MOUSE CONTROL ============================================================ */ // used by win_vid.c int mouse_buttons; int mouse_wheel_type; static int mouse_oldbuttonstate; static POINT current_pos; static int mx, my; static qboolean mouseactive; // qfalse when not focus app static qboolean restore_spi; static qboolean mouseinitialized; static int originalmouseparms[3], newmouseparms[3] = {0, 0, 0}; static qboolean mouseparmsvalid; static unsigned int mstate_di; static int window_center_x, window_center_y; static RECT window_rect; static LPDIRECTINPUT g_pdi; static LPDIRECTINPUTDEVICE g_pMouse; static HINSTANCE hInstDI; static qboolean dinput_initialized; static qboolean dinput_acquired; typedef struct MYDATA { LONG lX; // X axis goes here LONG lY; // Y axis goes here LONG lZ; // Z axis goes here BYTE bButtonA; // One button goes here BYTE bButtonB; // Another button goes here BYTE bButtonC; // Another button goes here BYTE bButtonD; // Another button goes here BYTE bButtonE; // Another button goes here BYTE bButtonF; // Another button goes here BYTE bButtonG; // Another button goes here BYTE bButtonH; // Another button goes here } MYDATA; // This structure corresponds to c_dfDIMouse2 in dinput8.lib // 0x80000000 is something undocumented but must be there, otherwise // IDirectInputDevice_SetDataFormat may fail. static DIOBJECTDATAFORMAT rgodf[] = { { &GUID_XAxis, FIELD_OFFSET(MYDATA, lX), DIDFT_AXIS | DIDFT_ANYINSTANCE, 0,}, { &GUID_YAxis, FIELD_OFFSET(MYDATA, lY), DIDFT_AXIS | DIDFT_ANYINSTANCE, 0,}, { &GUID_ZAxis, FIELD_OFFSET(MYDATA, lZ), 0x80000000 | DIDFT_AXIS | DIDFT_ANYINSTANCE, 0,}, { 0, FIELD_OFFSET(MYDATA, bButtonA), DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0,}, { 0, FIELD_OFFSET(MYDATA, bButtonB), DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0,}, { 0, FIELD_OFFSET(MYDATA, bButtonC), 0x80000000 | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0,}, { 0, FIELD_OFFSET(MYDATA, bButtonD), 0x80000000 | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0,}, { 0, FIELD_OFFSET(MYDATA, bButtonE), 0x80000000 | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0,}, { 0, FIELD_OFFSET(MYDATA, bButtonF), 0x80000000 | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0,}, { 0, FIELD_OFFSET(MYDATA, bButtonG), 0x80000000 | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0,}, { 0, FIELD_OFFSET(MYDATA, bButtonH), 0x80000000 | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0,}, }; #define NUM_OBJECTS (sizeof(rgodf) / sizeof(rgodf[0])) static DIDATAFORMAT df = { sizeof(DIDATAFORMAT), // this structure sizeof(DIOBJECTDATAFORMAT), // size of object data format DIDF_RELAXIS, // absolute axis coordinates sizeof(MYDATA), // device data size NUM_OBJECTS, // number of objects rgodf, // and here they are }; /* =========== IN_ActivateMouse Called when the window gains focus or changes in some way =========== */ void IN_ActivateMouse (void) { int width, height; if (!mouseinitialized) return; if (!in_mouse->integer) { mouseactive = qfalse; return; } if (mouseactive) return; mouseactive = qtrue; if (dinput_initialized) { if (g_pMouse) { if (cl_hwnd) if (FAILED(IDirectInputDevice_SetCooperativeLevel(g_pMouse, cl_hwnd, DISCL_EXCLUSIVE | DISCL_FOREGROUND))) { Com_DPrintf ("Couldn't set DI coop level\n"); return; } if (!dinput_acquired) { IDirectInputDevice_Acquire(g_pMouse); dinput_acquired = qtrue; } } return; } if (mouseparmsvalid) restore_spi = SystemParametersInfo (SPI_SETMOUSE, 0, newmouseparms, 0); width = GetSystemMetrics (SM_CXSCREEN); height = GetSystemMetrics (SM_CYSCREEN); GetWindowRect ( cl_hwnd, &window_rect); if (window_rect.left < 0) window_rect.left = 0; if (window_rect.top < 0) window_rect.top = 0; if (window_rect.right >= width) window_rect.right = width-1; if (window_rect.bottom >= height-1) window_rect.bottom = height-1; window_center_x = (window_rect.right + window_rect.left)/2; window_center_y = (window_rect.top + window_rect.bottom)/2; SetCursorPos (window_center_x, window_center_y); SetCapture (cl_hwnd); ClipCursor (&window_rect); while (ShowCursor (FALSE) >= 0); } /* =========== IN_DeactivateMouse Called when the window loses focus =========== */ void IN_DeactivateMouse (void) { if (!mouseinitialized) return; if (!mouseactive) return; mouseactive = qfalse; if (dinput_initialized) { if (g_pMouse) { if (dinput_acquired) { IDirectInputDevice_Unacquire(g_pMouse); dinput_acquired = qfalse; } if (cl_hwnd) if (FAILED(IDirectInputDevice_SetCooperativeLevel(g_pMouse, cl_hwnd, DISCL_EXCLUSIVE | DISCL_BACKGROUND))) { Com_DPrintf ("Couldn't set DI coop level\n"); return; } } return; } if (restore_spi) SystemParametersInfo (SPI_SETMOUSE, 0, originalmouseparms, 0); ClipCursor (NULL); ReleaseCapture (); while (ShowCursor (TRUE) < 0); } /* =========== IN_InitDInput =========== */ qboolean IN_InitDInput (void) { HRESULT hr; DIPROPDWORD dipdw = { { sizeof(DIPROPDWORD), // diph.dwSize sizeof(DIPROPHEADER), // diph.dwHeaderSize 0, // diph.dwObj DIPH_DEVICE, // diph.dwHow }, DINPUT_BUFFERSIZE, // dwData }; if (!hInstDI) { hInstDI = LoadLibrary("dinput.dll"); if (hInstDI == NULL) { Com_Printf ("Couldn't load dinput.dll\n"); return qfalse; } } if (!pDirectInputCreate) { pDirectInputCreate = (void *)GetProcAddress(hInstDI, "DirectInputCreateA"); if (!pDirectInputCreate) { Com_Printf ("Couldn't get DI proc addr\n"); return qfalse; } } // register with DirectInput and get an IDirectInput to play with hr = iDirectInputCreate(global_hInstance, DIRECTINPUT_VERSION, &g_pdi, NULL); if (FAILED(hr)) { Com_Printf ("DirectInputCreate failed\n"); return qfalse; } // obtain an interface to the system mouse device hr = IDirectInput_CreateDevice(g_pdi, &GUID_SysMouse, &g_pMouse, NULL); if (FAILED(hr)) { Com_Printf ("Couldn't open DI mouse device\n"); return qfalse; } // set the data format to "mouse format" hr = IDirectInputDevice_SetDataFormat(g_pMouse, &df); if (FAILED(hr)) { Com_Printf ("Couldn't set DI mouse format\n"); return qfalse; } // set the cooperativity level hr = IDirectInputDevice_SetCooperativeLevel(g_pMouse, cl_hwnd, DISCL_EXCLUSIVE | DISCL_FOREGROUND); if (FAILED(hr)) { Com_Printf ("Couldn't set DI coop level\n"); return qfalse; } // set the buffer size to DINPUT_BUFFERSIZE elements // the buffer size is a DWORD property associated with the device hr = IDirectInputDevice_SetProperty(g_pMouse, DIPROP_BUFFERSIZE, &dipdw.diph); if (FAILED(hr)) { Com_DPrintf ("Couldn't set DI buffersize\n"); return qfalse; } return qtrue; } /* =========== IN_ShutdownDInput =========== */ void IN_ShutdownDInput (void) { if( g_pMouse ) { IDirectInputDevice_SetCooperativeLevel( g_pMouse, cl_hwnd, DISCL_NONEXCLUSIVE | DISCL_BACKGROUND ); IDirectInputDevice_Release( g_pMouse ); } if( g_pdi ) IDirectInput_Release( g_pdi ); if( hInstDI ) FreeLibrary( hInstDI ); g_pMouse = NULL; g_pdi = NULL; hInstDI = NULL; } /* =========== IN_StartupMouse =========== */ void IN_StartupMouse (void) { cvar_t *cv; cv = Cvar_Get ("in_initmouse", "1", CVAR_NOSET); if( !cv->integer ) return; dinput_initialized = qfalse; cv = Cvar_Get ("in_dinput", "1", CVAR_ARCHIVE); if( cv->integer ) dinput_initialized = IN_InitDInput (); if (dinput_initialized) Com_Printf ("DirectInput initialized\n"); else Com_Printf ("DirectInput not initialized, using standard input\n"); mouseinitialized = qtrue; mouseparmsvalid = SystemParametersInfo (SPI_GETMOUSE, 0, originalmouseparms, 0); mouse_buttons = 8; mouse_wheel_type = MWHEEL_UNKNOWN; } /* =========== IN_MouseEvent =========== */ void IN_MouseEvent (int mstate) { int i; if (!mouseinitialized || dinput_initialized) return; if( (cls.key_dest == key_console) && !in_grabinconsole->integer ) return; // perform button actions for (i=0 ; i 0) { Key_Event( K_MWHEELUP, qtrue, sys_msg_time ); Key_Event( K_MWHEELUP, qfalse, sys_msg_time ); } else { Key_Event( K_MWHEELDOWN, qtrue, sys_msg_time ); Key_Event( K_MWHEELDOWN, qfalse, sys_msg_time ); } } break; case DIMOFS_BUTTON0: case DIMOFS_BUTTON1: case DIMOFS_BUTTON2: case DIMOFS_BUTTON3: case DIMOFS_BUTTON0+4: case DIMOFS_BUTTON0+5: case DIMOFS_BUTTON0+6: case DIMOFS_BUTTON0+7: if (od.dwData & 0x80) mstate_di |= (1<<(od.dwOfs-DIMOFS_BUTTON0)); else mstate_di &= ~(1<<(od.dwOfs-DIMOFS_BUTTON0)); break; } } dinput_initialized = qfalse; // FIXME... IN_MouseEvent (mstate_di); dinput_initialized = qtrue; } else { // find mouse movement if (!GetCursorPos (¤t_pos)) return; mx = current_pos.x - window_center_x; my = current_pos.y - window_center_y; // force the mouse to the center, so there's room to move if (mx || my) SetCursorPos (window_center_x, window_center_y); } // wsw : pb : moved mousemove to cl_input (q3 like) CL_MouseMove( cmd, mx, my ); /* CUT THERE if( cls.key_dest == key_menu ) { CL_UIModule_MouseMove( mx, my ); return; } if( (cls.key_dest == key_console) && !in_grabinconsole->integer ) return; #if 0 if (!mx && !my) return; #endif if (m_filter->integer) { 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->integer && mlooking )) cmd->sidemove += m_side->value * mouse_x; else cl.viewangles[YAW] -= m_yaw->value * mouse_x; if ( (mlooking || cl_freelook->integer) && !(in_strafe.state & 1)) cl.viewangles[PITCH] += m_pitch->value * mouse_y; else cmd->forwardmove -= m_forward->value * mouse_y; */ } /* ========================================================================= VIEW CENTERING ========================================================================= */ cvar_t *v_centermove; cvar_t *v_centerspeed; /* =========== Joystick looking =========== */ static void Joy_JLookDown (void) { jlooking = qtrue; } static void Joy_JLookUp (void) { jlooking = qfalse; if( !cl_freelook->integer && lookspring->integer ) IN_CenterView (); } /* =========== IN_Init =========== */ void IN_Init (void) { Com_Printf ("\n------- input initialization -------\n"); // mouse variables in_mouse = Cvar_Get ("in_mouse", "1", CVAR_ARCHIVE); in_grabinconsole = Cvar_Get ("in_grabinconsole", "0", CVAR_ARCHIVE); // joystick variables in_joystick = Cvar_Get ("in_joystick", "0", CVAR_ARCHIVE); joy_name = Cvar_Get ("joy_name", "joystick", 0); joy_advanced = Cvar_Get ("joy_advanced", "0", 0); joy_advaxisx = Cvar_Get ("joy_advaxisx", "0", 0); joy_advaxisy = Cvar_Get ("joy_advaxisy", "0", 0); joy_advaxisz = Cvar_Get ("joy_advaxisz", "0", 0); joy_advaxisr = Cvar_Get ("joy_advaxisr", "0", 0); joy_advaxisu = Cvar_Get ("joy_advaxisu", "0", 0); joy_advaxisv = Cvar_Get ("joy_advaxisv", "0", 0); joy_forwardthreshold = Cvar_Get ("joy_forwardthreshold", "0.15", 0); joy_sidethreshold = Cvar_Get ("joy_sidethreshold", "0.15", 0); joy_upthreshold = Cvar_Get ("joy_upthreshold", "0.15", 0); joy_pitchthreshold = Cvar_Get ("joy_pitchthreshold", "0.15", 0); joy_yawthreshold = Cvar_Get ("joy_yawthreshold", "0.15", 0); joy_forwardsensitivity = Cvar_Get ("joy_forwardsensitivity", "-1", 0); joy_sidesensitivity = Cvar_Get ("joy_sidesensitivity", "-1", 0); joy_upsensitivity = Cvar_Get ("joy_upsensitivity", "-1", 0); joy_pitchsensitivity = Cvar_Get ("joy_pitchsensitivity", "1", 0); joy_yawsensitivity = Cvar_Get ("joy_yawsensitivity", "-1", 0); // centering v_centermove = Cvar_Get ("v_centermove", "0.15", 0); v_centerspeed = Cvar_Get ("v_centerspeed", "500", 0); Cmd_AddCommand ("+jlook", Joy_JLookDown); Cmd_AddCommand ("-jlook", Joy_JLookUp); Cmd_AddCommand ("joy_advancedupdate", Joy_AdvancedUpdate_f); IN_StartupMouse (); IN_StartupJoystick (); Com_Printf ("------------------------------------\n"); } /* =========== IN_Shutdown =========== */ void IN_Shutdown (void) { IN_DeactivateMouse (); if (dinput_initialized) IN_ShutdownDInput (); Cmd_RemoveCommand ("+jlook"); Cmd_RemoveCommand ("-jlook"); Cmd_RemoveCommand ("joy_advancedupdate"); } /* =========== IN_Restart =========== */ void IN_Restart (void) { IN_Shutdown (); IN_Init (); } /* =========== IN_Activate Called when the main window gains or loses focus. The window may have been destroyed and recreated between a deactivate and an activate. =========== */ void IN_Activate (qboolean active) { in_appactive = active; mouseactive = !active; // force a new window check or turn off } /* ================== IN_Frame Called every frame, even if not generating commands ================== */ void IN_Frame(void) { if( !mouseinitialized ) return; if( !in_mouse || !in_appactive ) { IN_DeactivateMouse(); return; } IN_ActivateMouse(); } /* =========== IN_Move =========== */ void IN_Move( usercmd_t *cmd ) { IN_MouseMove( cmd ); if( ActiveApp ) IN_JoyMove( cmd ); } /* =================== IN_ClearStates =================== */ void IN_ClearStates (void) { mouse_oldbuttonstate = 0; } /* ========================================================================= JOYSTICK ========================================================================= */ /* =============== IN_StartupJoystick =============== */ void IN_StartupJoystick (void) { int numdevs; JOYCAPS jc; MMRESULT mmr=0; cvar_t *cv; // assume no joystick joy_avail = qfalse; // abort startup if user requests no joystick cv = Cvar_Get ("in_initjoy", "1", CVAR_NOSET); if ( !cv->integer ) return; // verify joystick driver is present if ((numdevs = joyGetNumDevs ()) == 0) { // Com_Printf ("joystick not found -- driver not present\n"); return; } // cycle through the joystick ids for the first valid one for (joy_id=0 ; joy_idinteger == 0) { // default joystick initialization // 2 axes only with joystick control dwAxisMap[JOY_AXIS_X] = AxisTurn; // dwControlMap[JOY_AXIS_X] = JOY_ABSOLUTE_AXIS; dwAxisMap[JOY_AXIS_Y] = AxisForward; // dwControlMap[JOY_AXIS_Y] = JOY_ABSOLUTE_AXIS; } else { if (strcmp (joy_name->string, "joystick") != 0) { // notify user of advanced controller Com_Printf ("\n%s configured\n\n", joy_name->string); } // advanced initialization here // data supplied by user via joy_axisn cvars dwTemp = (DWORD) joy_advaxisx->integer; dwAxisMap[JOY_AXIS_X] = dwTemp & 0x0000000f; dwControlMap[JOY_AXIS_X] = dwTemp & JOY_RELATIVE_AXIS; dwTemp = (DWORD) joy_advaxisy->integer; dwAxisMap[JOY_AXIS_Y] = dwTemp & 0x0000000f; dwControlMap[JOY_AXIS_Y] = dwTemp & JOY_RELATIVE_AXIS; dwTemp = (DWORD) joy_advaxisz->integer; dwAxisMap[JOY_AXIS_Z] = dwTemp & 0x0000000f; dwControlMap[JOY_AXIS_Z] = dwTemp & JOY_RELATIVE_AXIS; dwTemp = (DWORD) joy_advaxisr->integer; dwAxisMap[JOY_AXIS_R] = dwTemp & 0x0000000f; dwControlMap[JOY_AXIS_R] = dwTemp & JOY_RELATIVE_AXIS; dwTemp = (DWORD) joy_advaxisu->integer; dwAxisMap[JOY_AXIS_U] = dwTemp & 0x0000000f; dwControlMap[JOY_AXIS_U] = dwTemp & JOY_RELATIVE_AXIS; dwTemp = (DWORD) joy_advaxisv->integer; dwAxisMap[JOY_AXIS_V] = dwTemp & 0x0000000f; dwControlMap[JOY_AXIS_V] = dwTemp & JOY_RELATIVE_AXIS; } // compute the axes to collect from DirectInput joy_flags = JOY_RETURNCENTERED | JOY_RETURNBUTTONS | JOY_RETURNPOV; for (i = 0; i < JOY_MAX_AXES; i++) { if (dwAxisMap[i] != AxisNada) joy_flags |= dwAxisFlags[i]; } } /* =========== IN_Commands =========== */ void IN_Commands( void ) { unsigned i; int key_index; DWORD buttonstate, povstate; if( !joy_avail ) return; // loop through the joystick buttons // key a joystick event or auxillary event for higher number buttons for each state change buttonstate = ji.dwButtons; for( i=0 ; i < joy_numbuttons ; i++ ) { if( (buttonstate & (1<integer) return; // collect the joystick data, if possible if (IN_ReadJoystick () != qtrue) return; // wsw : jal : decide walk in server side //if ( (in_speed.state & 1) ^ cl_run->integer) // speed = 2; //else speed = 1; //aspeed = speed * cls.frametime; aspeed = cls.frametime; // loop through the axes for (i = 0; i < JOY_MAX_AXES; i++) { // get the floating point zero-centered, potentially-inverted data for the current axis fAxisValue = (float) *pdwRawValue[i]; // move centerpoint to zero fAxisValue -= 32768.0; // convert range from -32768..32767 to -1..1 fAxisValue /= 32768.0; switch (dwAxisMap[i]) { case AxisForward: if ((joy_advanced->integer == 0) && jlooking) { // user wants forward control to become look control if (fabs(fAxisValue) > joy_pitchthreshold->value) { // if mouse invert is on, invert the joystick pitch value // only absolute control support here (joy_advanced is qfalse) 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; } } else { // user wants forward control to be forward control if (fabs(fAxisValue) > joy_forwardthreshold->value) cmd->forwardmove += (fAxisValue * joy_forwardsensitivity->value) * speed * cl_forwardspeed->value; } break; case AxisSide: if (fabs(fAxisValue) > joy_sidethreshold->value) cmd->sidemove += (fAxisValue * joy_sidesensitivity->value) * speed * cl_sidespeed->value; break; case AxisUp: if (fabs(fAxisValue) > joy_upthreshold->value) cmd->upmove += (fAxisValue * joy_upsensitivity->value) * speed * cl_upspeed->value; break; case AxisTurn: if ((in_strafe.state & 1) || (lookstrafe->value && jlooking)) { // user wants turn control to become side control if (fabs(fAxisValue) > joy_sidethreshold->value) cmd->sidemove -= (fAxisValue * joy_sidesensitivity->value) * speed * cl_sidespeed->value; } else { // user wants turn control to be turn control if (fabs(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 (jlooking) { if (fabs(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; } } break; default: break; } } }