xash3d-fwgs/engine/common/input.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( &current_pos.x, &current_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();
}