mirror of
https://github.com/w23/xash3d-fwgs
synced 2024-12-15 21:50:59 +01:00
639 lines
13 KiB
C
639 lines
13 KiB
C
/*
|
|
input.c - win32 input devices
|
|
Copyright (C) 2007 Uncle Mike
|
|
|
|
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 3 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.
|
|
*/
|
|
|
|
#include "common.h"
|
|
#include "input.h"
|
|
#include "client.h"
|
|
#include "vgui_draw.h"
|
|
#include "gl_local.h"
|
|
|
|
#ifdef XASH_SDL
|
|
#include <SDL.h>
|
|
#endif
|
|
|
|
#ifdef _WIN32
|
|
#include "windows.h"
|
|
#endif
|
|
|
|
void* in_mousecursor;
|
|
qboolean in_mouseactive; // false when not focus app
|
|
qboolean in_mouseinitialized;
|
|
qboolean in_mouse_suspended;
|
|
POINT in_lastvalidpos;
|
|
qboolean in_mouse_savedpos;
|
|
static struct inputstate_s
|
|
{
|
|
float lastpitch, lastyaw;
|
|
} inputstate;
|
|
|
|
extern convar_t *vid_fullscreen;
|
|
convar_t *m_enginemouse;
|
|
convar_t *m_pitch;
|
|
convar_t *m_yaw;
|
|
|
|
convar_t *m_enginesens;
|
|
convar_t *m_ignore;
|
|
convar_t *cl_forwardspeed;
|
|
convar_t *cl_sidespeed;
|
|
convar_t *cl_backspeed;
|
|
convar_t *look_filter;
|
|
|
|
/*
|
|
===========
|
|
IN_StartupMouse
|
|
===========
|
|
*/
|
|
void IN_StartupMouse( void )
|
|
{
|
|
m_ignore = Cvar_Get( "m_ignore", DEFAULT_M_IGNORE, FCVAR_ARCHIVE , "ignore mouse events" );
|
|
|
|
m_enginemouse = Cvar_Get( "m_enginemouse", "0", FCVAR_ARCHIVE, "read mouse events in engine instead of client" );
|
|
m_enginesens = Cvar_Get( "m_enginesens", "0.3", FCVAR_ARCHIVE, "mouse sensitivity, when m_enginemouse enabled" );
|
|
m_pitch = Cvar_Get( "m_pitch", "0.022", FCVAR_ARCHIVE, "mouse pitch value" );
|
|
m_yaw = Cvar_Get( "m_yaw", "0.022", FCVAR_ARCHIVE, "mouse yaw value" );
|
|
look_filter = Cvar_Get( "look_filter", "0", FCVAR_ARCHIVE, "filter look events making it smoother" );
|
|
|
|
// You can use -nomouse argument to prevent using mouse from client
|
|
// -noenginemouse will disable all mouse input
|
|
if( Sys_CheckParm( "-noenginemouse" )) return;
|
|
|
|
in_mouseinitialized = true;
|
|
}
|
|
|
|
static void IN_ActivateCursor( void )
|
|
{
|
|
if( cls.key_dest == key_menu )
|
|
{
|
|
#ifdef XASH_SDL
|
|
SDL_SetCursor( in_mousecursor );
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void IN_SetCursor( void *hCursor )
|
|
{
|
|
in_mousecursor = hCursor;
|
|
|
|
IN_ActivateCursor();
|
|
}
|
|
|
|
/*
|
|
===========
|
|
IN_MouseSavePos
|
|
|
|
Save mouse pos before state change e.g. changelevel
|
|
===========
|
|
*/
|
|
void IN_MouseSavePos( void )
|
|
{
|
|
if( !in_mouseactive )
|
|
return;
|
|
|
|
#ifdef XASH_SDL
|
|
SDL_GetMouseState( &in_lastvalidpos.x, &in_lastvalidpos.y );
|
|
in_mouse_savedpos = true;
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
===========
|
|
IN_MouseRestorePos
|
|
|
|
Restore right position for background
|
|
===========
|
|
*/
|
|
void IN_MouseRestorePos( void )
|
|
{
|
|
if( !in_mouse_savedpos )
|
|
return;
|
|
|
|
#ifdef XASH_SDL
|
|
SDL_WarpMouseInWindow( host.hWnd, in_lastvalidpos.x, in_lastvalidpos.y );
|
|
#endif
|
|
|
|
in_mouse_savedpos = false;
|
|
}
|
|
|
|
/*
|
|
===========
|
|
IN_ToggleClientMouse
|
|
|
|
Called when key_dest is changed
|
|
===========
|
|
*/
|
|
void IN_ToggleClientMouse( int newstate, int oldstate )
|
|
{
|
|
if( newstate == oldstate ) return;
|
|
|
|
if( oldstate == key_game )
|
|
{
|
|
clgame.dllFuncs.IN_DeactivateMouse();
|
|
}
|
|
else if( newstate == key_game )
|
|
{
|
|
// reset mouse pos, so cancel effect in game
|
|
#ifdef XASH_SDL
|
|
if( touch_enable->value )
|
|
{
|
|
SDL_SetRelativeMouseMode( SDL_FALSE );
|
|
SDL_SetWindowGrab( host.hWnd, SDL_FALSE );
|
|
}
|
|
else
|
|
{
|
|
SDL_WarpMouseInWindow( host.hWnd, host.window_center_x, host.window_center_y );
|
|
SDL_SetWindowGrab( host.hWnd, SDL_TRUE );
|
|
if( clgame.dllFuncs.pfnLookEvent )
|
|
SDL_SetRelativeMouseMode( SDL_TRUE );
|
|
}
|
|
#endif // XASH_SDL
|
|
if( cls.initialized )
|
|
clgame.dllFuncs.IN_ActivateMouse();
|
|
}
|
|
|
|
if( ( newstate == key_menu || newstate == key_console || newstate == key_message ) && ( !CL_IsBackgroundMap() || CL_IsBackgroundDemo( )))
|
|
{
|
|
#ifdef XASH_SDL
|
|
SDL_SetWindowGrab(host.hWnd, SDL_FALSE);
|
|
if( clgame.dllFuncs.pfnLookEvent )
|
|
SDL_SetRelativeMouseMode( SDL_FALSE );
|
|
#endif
|
|
#ifdef __ANDROID__
|
|
Android_ShowMouse( true );
|
|
#endif
|
|
#ifdef USE_EVDEV
|
|
Evdev_SetGrab( false );
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
#ifdef __ANDROID__
|
|
Android_ShowMouse( false );
|
|
#endif
|
|
#ifdef USE_EVDEV
|
|
Evdev_SetGrab( true );
|
|
#endif
|
|
}
|
|
}
|
|
|
|
/*
|
|
===========
|
|
IN_ActivateMouse
|
|
|
|
Called when the window gains focus or changes in some way
|
|
===========
|
|
*/
|
|
void IN_ActivateMouse( qboolean force )
|
|
{
|
|
int width, height;
|
|
static int oldstate;
|
|
|
|
if( !in_mouseinitialized )
|
|
return;
|
|
|
|
if( CL_Active() && host.mouse_visible && !force )
|
|
return; // VGUI controls
|
|
|
|
if( cls.key_dest == key_menu && !Cvar_VariableInteger( "fullscreen" ))
|
|
{
|
|
// check for mouse leave-entering
|
|
if( !in_mouse_suspended && !UI_MouseInRect( ))
|
|
in_mouse_suspended = true;
|
|
|
|
if( oldstate != in_mouse_suspended )
|
|
{
|
|
if( in_mouse_suspended )
|
|
{
|
|
#ifdef XASH_SDL
|
|
SDL_ShowCursor( false );
|
|
#endif
|
|
UI_ShowCursor( false );
|
|
}
|
|
}
|
|
|
|
oldstate = in_mouse_suspended;
|
|
|
|
if( in_mouse_suspended )
|
|
{
|
|
in_mouse_suspended = false;
|
|
in_mouseactive = false; // re-initialize mouse
|
|
UI_ShowCursor( true );
|
|
}
|
|
}
|
|
|
|
if( in_mouseactive ) return;
|
|
in_mouseactive = true;
|
|
|
|
if( UI_IsVisible( )) return;
|
|
|
|
if( cls.key_dest == key_game )
|
|
{
|
|
clgame.dllFuncs.IN_ActivateMouse();
|
|
#ifdef XASH_SDL
|
|
SDL_GetRelativeMouseState( 0, 0 ); // Reset mouse position
|
|
#endif
|
|
}
|
|
}
|
|
|
|
/*
|
|
===========
|
|
IN_DeactivateMouse
|
|
|
|
Called when the window loses focus
|
|
===========
|
|
*/
|
|
void IN_DeactivateMouse( void )
|
|
{
|
|
if( !in_mouseinitialized || !in_mouseactive )
|
|
return;
|
|
|
|
if( cls.key_dest == key_game )
|
|
{
|
|
clgame.dllFuncs.IN_DeactivateMouse();
|
|
}
|
|
|
|
in_mouseactive = false;
|
|
#ifdef XASH_SDL
|
|
SDL_SetWindowGrab( host.hWnd, SDL_FALSE );
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
================
|
|
IN_MouseMove
|
|
================
|
|
*/
|
|
void IN_MouseMove( void )
|
|
{
|
|
POINT current_pos;
|
|
|
|
if( !in_mouseinitialized || !in_mouseactive || !UI_IsVisible( ))
|
|
return;
|
|
|
|
// find mouse movement
|
|
#ifdef XASH_SDL
|
|
SDL_GetMouseState( ¤t_pos.x, ¤t_pos.y );
|
|
#endif
|
|
|
|
VGui_MouseMove( current_pos.x, current_pos.y );
|
|
|
|
// HACKHACK: show cursor in UI, as mainui doesn't call
|
|
// platform-dependent SetCursor anymore
|
|
#ifdef XASH_SDL
|
|
if( UI_IsVisible() )
|
|
SDL_ShowCursor( SDL_TRUE );
|
|
#endif
|
|
|
|
// if the menu is visible, move the menu cursor
|
|
UI_MouseMove( current_pos.x, current_pos.y );
|
|
|
|
IN_ActivateCursor();
|
|
}
|
|
|
|
/*
|
|
===========
|
|
IN_MouseEvent
|
|
===========
|
|
*/
|
|
void IN_MouseEvent( void )
|
|
{
|
|
int i;
|
|
|
|
if( !in_mouseinitialized || !in_mouseactive )
|
|
return;
|
|
|
|
if( m_ignore->value )
|
|
return;
|
|
|
|
if( cls.key_dest == key_game )
|
|
{
|
|
#if defined( XASH_SDL )
|
|
static qboolean ignore; // igonre mouse warp event
|
|
int x, y;
|
|
SDL_GetMouseState(&x, &y);
|
|
if( host.mouse_visible )
|
|
SDL_ShowCursor( SDL_TRUE );
|
|
else
|
|
SDL_ShowCursor( SDL_FALSE );
|
|
|
|
if( x < host.window_center_x / 2 ||
|
|
y < host.window_center_y / 2 ||
|
|
x > host.window_center_x + host.window_center_x / 2 ||
|
|
y > host.window_center_y + host.window_center_y / 2 )
|
|
{
|
|
SDL_WarpMouseInWindow(host.hWnd, host.window_center_x, host.window_center_y);
|
|
ignore = 1; // next mouse event will be mouse warp
|
|
return;
|
|
}
|
|
|
|
if ( !ignore )
|
|
{
|
|
if( !m_enginemouse->value )
|
|
{
|
|
// a1ba: mouse keys are now separated
|
|
// so pass 0 here
|
|
clgame.dllFuncs.IN_MouseEvent( 0 );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SDL_GetRelativeMouseState( 0, 0 ); // reset relative state
|
|
ignore = 0;
|
|
}
|
|
#endif
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
#if defined(XASH_SDL) && !defined(_WIN32)
|
|
SDL_SetRelativeMouseMode( SDL_FALSE );
|
|
SDL_ShowCursor( SDL_TRUE );
|
|
#endif
|
|
IN_MouseMove();
|
|
}
|
|
}
|
|
|
|
/*
|
|
===========
|
|
IN_Shutdown
|
|
===========
|
|
*/
|
|
void IN_Shutdown( void )
|
|
{
|
|
IN_DeactivateMouse( );
|
|
|
|
#ifdef XASH_USE_EVDEV
|
|
Evdev_Shutdown();
|
|
#endif
|
|
}
|
|
|
|
|
|
/*
|
|
===========
|
|
IN_Init
|
|
===========
|
|
*/
|
|
void IN_Init( void )
|
|
{
|
|
cl_forwardspeed = Cvar_Get( "cl_forwardspeed", "400", FCVAR_ARCHIVE | FCVAR_CLIENTDLL, "Default forward move speed" );
|
|
cl_backspeed = Cvar_Get( "cl_backspeed", "400", FCVAR_ARCHIVE | FCVAR_CLIENTDLL, "Default back move speed" );
|
|
cl_sidespeed = Cvar_Get( "cl_sidespeed", "400", FCVAR_ARCHIVE | FCVAR_CLIENTDLL, "Default side move speed" );
|
|
|
|
if( !Host_IsDedicated() )
|
|
{
|
|
IN_StartupMouse( );
|
|
|
|
Joy_Init(); // common joystick support init
|
|
|
|
#ifdef XASH_USE_EVDEV
|
|
Evdev_Init();
|
|
#endif
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
IN_JoyMove
|
|
|
|
Common function for engine joystick movement
|
|
|
|
-1 < forwardmove < 1, -1 < sidemove < 1
|
|
|
|
================
|
|
*/
|
|
|
|
#define F (1U << 0) // Forward
|
|
#define B (1U << 1) // Back
|
|
#define L (1U << 2) // Left
|
|
#define R (1U << 3) // Right
|
|
#define T (1U << 4) // Forward stop
|
|
#define S (1U << 5) // Side stop
|
|
void IN_JoyAppendMove( usercmd_t *cmd, float forwardmove, float sidemove )
|
|
{
|
|
static uint moveflags = T | S;
|
|
|
|
if( forwardmove ) cmd->forwardmove = forwardmove * cl_forwardspeed->value;
|
|
if( sidemove ) cmd->sidemove = sidemove * cl_sidespeed->value;
|
|
|
|
if( forwardmove )
|
|
{
|
|
moveflags &= ~T;
|
|
}
|
|
else if( !( moveflags & T ) )
|
|
{
|
|
Cmd_ExecuteString( "-back" );
|
|
Cmd_ExecuteString( "-forward" );
|
|
moveflags |= T;
|
|
}
|
|
|
|
if( sidemove )
|
|
{
|
|
moveflags &= ~S;
|
|
}
|
|
else if( !( moveflags & S ) )
|
|
{
|
|
Cmd_ExecuteString( "-moveleft" );
|
|
Cmd_ExecuteString( "-moveright" );
|
|
moveflags |= S;
|
|
}
|
|
|
|
if ( forwardmove > 0.7 && !( moveflags & F ))
|
|
{
|
|
moveflags |= F;
|
|
Cmd_ExecuteString( "+forward" );
|
|
}
|
|
else if ( forwardmove < 0.7 && ( moveflags & F ))
|
|
{
|
|
moveflags &= ~F;
|
|
Cmd_ExecuteString( "-forward" );
|
|
}
|
|
|
|
if ( forwardmove < -0.7 && !( moveflags & B ))
|
|
{
|
|
moveflags |= B;
|
|
Cmd_ExecuteString( "+back" );
|
|
}
|
|
else if ( forwardmove > -0.7 && ( moveflags & B ))
|
|
{
|
|
moveflags &= ~B;
|
|
Cmd_ExecuteString( "-back" );
|
|
}
|
|
|
|
if ( sidemove > 0.9 && !( moveflags & R ))
|
|
{
|
|
moveflags |= R;
|
|
Cmd_ExecuteString( "+moveright" );
|
|
}
|
|
else if ( sidemove < 0.9 && ( moveflags & R ))
|
|
{
|
|
moveflags &= ~R;
|
|
Cmd_ExecuteString( "-moveright" );
|
|
}
|
|
|
|
if ( sidemove < -0.9 && !( moveflags & L ))
|
|
{
|
|
moveflags |= L;
|
|
Cmd_ExecuteString( "+moveleft" );
|
|
}
|
|
else if ( sidemove > -0.9 && ( moveflags & L ))
|
|
{
|
|
moveflags &= ~L;
|
|
Cmd_ExecuteString( "-moveleft" );
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
IN_EngineAppendMove
|
|
|
|
Called from cl_main.c after generating command in client
|
|
================
|
|
*/
|
|
void IN_EngineAppendMove( float frametime, usercmd_t *cmd, qboolean active )
|
|
{
|
|
float forward, side, dpitch, dyaw;
|
|
|
|
if( clgame.dllFuncs.pfnLookEvent )
|
|
return;
|
|
|
|
if( cls.key_dest != key_game || cl.paused || cl.intermission )
|
|
return;
|
|
|
|
forward = side = dpitch = dyaw = 0;
|
|
|
|
if(active)
|
|
{
|
|
float sensitivity = ( (float)RI.fov_x / (float)90.0f );
|
|
#if XASH_INPUT == INPUT_SDL
|
|
if( m_enginemouse->value && !m_ignore->value )
|
|
{
|
|
int mouse_x, mouse_y;
|
|
SDL_GetRelativeMouseState( &mouse_x, &mouse_y );
|
|
RI.viewangles[PITCH] += mouse_y * m_pitch->value * sensitivity;
|
|
RI.viewangles[YAW] -= mouse_x * m_yaw->value * sensitivity;
|
|
}
|
|
#endif
|
|
#ifdef __ANDROID__
|
|
if( !m_ignore->value )
|
|
{
|
|
float mouse_x, mouse_y;
|
|
Android_MouseMove( &mouse_x, &mouse_y );
|
|
RI.viewangles[PITCH] += mouse_y * m_pitch->value * sensitivity;
|
|
RI.viewangles[YAW] -= mouse_x * m_yaw->value * sensitivity;
|
|
}
|
|
#endif
|
|
Joy_FinalizeMove( &forward, &side, &dyaw, &dpitch );
|
|
IN_TouchMove( &forward, &side, &dyaw, &dpitch );
|
|
IN_JoyAppendMove( cmd, forward, side );
|
|
#ifdef USE_EVDEV
|
|
IN_EvdevMove( &dyaw, &dpitch );
|
|
#endif
|
|
if( look_filter->value )
|
|
{
|
|
dpitch = ( inputstate.lastpitch + dpitch ) / 2;
|
|
dyaw = ( inputstate.lastyaw + dyaw ) / 2;
|
|
inputstate.lastpitch = dpitch;
|
|
inputstate.lastyaw = dyaw;
|
|
}
|
|
|
|
RI.viewangles[YAW] += dyaw * sensitivity;
|
|
RI.viewangles[PITCH] += dpitch * sensitivity;
|
|
RI.viewangles[PITCH] = bound( -90, RI.viewangles[PITCH], 90 );
|
|
}
|
|
}
|
|
|
|
/*
|
|
==================
|
|
Host_InputFrame
|
|
|
|
Called every frame, even if not generating commands
|
|
==================
|
|
*/
|
|
void Host_InputFrame( void )
|
|
{
|
|
qboolean shutdownMouse = false;
|
|
float forward = 0, side = 0, pitch = 0, yaw = 0;
|
|
|
|
Sys_SendKeyEvents ();
|
|
|
|
#ifdef XASH_USE_EVDEV
|
|
IN_EvdevFrame();
|
|
#endif
|
|
|
|
if( clgame.dllFuncs.pfnLookEvent )
|
|
{
|
|
int dx, dy;
|
|
|
|
#ifndef __ANDROID__
|
|
if( in_mouseinitialized && !m_ignore->value )
|
|
{
|
|
SDL_GetRelativeMouseState( &dx, &dy );
|
|
pitch += dy * m_pitch->value, yaw -= dx * m_yaw->value; //mouse speed
|
|
}
|
|
#endif
|
|
|
|
#ifdef __ANDROID__
|
|
if( !m_ignore->value )
|
|
{
|
|
float mouse_x, mouse_y;
|
|
Android_MouseMove( &mouse_x, &mouse_y );
|
|
pitch += mouse_y * m_pitch->value, yaw -= mouse_x * m_yaw->value; //mouse speed
|
|
}
|
|
#endif
|
|
|
|
Joy_FinalizeMove( &forward, &side, &yaw, &pitch );
|
|
IN_TouchMove( &forward, &side, &yaw, &pitch );
|
|
#ifdef USE_EVDEV
|
|
IN_EvdevMove( &yaw, &pitch );
|
|
#endif
|
|
if( look_filter->value )
|
|
{
|
|
pitch = ( inputstate.lastpitch + pitch ) / 2;
|
|
yaw = ( inputstate.lastyaw + yaw ) / 2;
|
|
inputstate.lastpitch = pitch;
|
|
inputstate.lastyaw = yaw;
|
|
}
|
|
|
|
if( cls.key_dest == key_game )
|
|
{
|
|
clgame.dllFuncs.pfnLookEvent( yaw, pitch );
|
|
clgame.dllFuncs.pfnMoveEvent( forward, side );
|
|
}
|
|
}
|
|
|
|
Cbuf_Execute ();
|
|
|
|
if( !in_mouseinitialized )
|
|
return;
|
|
|
|
if( host.status != HOST_FRAME )
|
|
{
|
|
IN_DeactivateMouse();
|
|
return;
|
|
}
|
|
|
|
// release mouse during pause or console typeing
|
|
if( cl.paused && cls.key_dest == key_game )
|
|
shutdownMouse = true;
|
|
|
|
if( shutdownMouse && !Cvar_VariableInteger( "fullscreen" ))
|
|
{
|
|
IN_DeactivateMouse();
|
|
return;
|
|
}
|
|
|
|
IN_ActivateMouse( false );
|
|
IN_MouseMove();
|
|
}
|