mirror of
https://github.com/w23/xash3d-fwgs
synced 2024-12-15 05:29:51 +01:00
Engine input port. Incomplete integration of touch, gamepad, evdev input
This commit is contained in:
parent
990d526a07
commit
4189af8b50
@ -62,6 +62,10 @@ typedef struct cldll_func_s
|
||||
// Xash3D extension
|
||||
int (*pfnGetRenderInterface)( int version, render_api_t *renderfuncs, render_interface_t *callback );
|
||||
void (*pfnClipMoveToEntity)( struct physent_s *pe, const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end, struct pmtrace_s *tr );
|
||||
// Xash3D FWGS extension
|
||||
int (*pfnTouchEvent)( int type, int fingerID, float x, float y, float dx, float dy );
|
||||
void (*pfnMoveEvent)( float forwardmove, float sidemove );
|
||||
void (*pfnLookEvent)( float relyaw, float relpitch );
|
||||
} cldll_func_t;
|
||||
|
||||
#endif//CDLL_EXP_H
|
||||
#endif//CDLL_EXP_H
|
||||
|
@ -88,6 +88,9 @@ static dllfunc_t cdll_new_exports[] = // allowed only in SDK 2.3 and higher
|
||||
{ "HUD_ChatInputPosition", (void **)&clgame.dllFuncs.pfnChatInputPosition },
|
||||
{ "HUD_GetRenderInterface", (void **)&clgame.dllFuncs.pfnGetRenderInterface }, // Xash3D ext
|
||||
{ "HUD_ClipMoveToEntity", (void **)&clgame.dllFuncs.pfnClipMoveToEntity }, // Xash3D ext
|
||||
{ "IN_ClientTouchEvent", (void **)&clgame.dllFuncs.pfnTouchEvent}, // Xash3D FWGS ext
|
||||
{ "IN_ClientMoveEvent", (void **)&clgame.dllFuncs.pfnMoveEvent}, // Xash3D FWGS ext
|
||||
{ "IN_ClientLookEvent", (void **)&clgame.dllFuncs.pfnLookEvent}, // Xash3D FWGS ext
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
|
@ -695,6 +695,7 @@ extern convar_t *scr_loading;
|
||||
extern convar_t *v_dark; // start from dark
|
||||
extern convar_t *net_graph;
|
||||
extern convar_t *rate;
|
||||
extern convar_t *m_ignore;
|
||||
|
||||
//=============================================================================
|
||||
|
||||
@ -1047,4 +1048,4 @@ void SCR_RunCinematic( void );
|
||||
void SCR_StopCinematic( void );
|
||||
void CL_PlayVideo_f( void );
|
||||
|
||||
#endif//CLIENT_H
|
||||
#endif//CLIENT_H
|
||||
|
337
engine/client/in_evdev.c
Normal file
337
engine/client/in_evdev.c
Normal file
@ -0,0 +1,337 @@
|
||||
/*
|
||||
in_evdev.c - linux evdev interface support
|
||||
Copyright (C) 2015-2018 mittorn
|
||||
|
||||
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.
|
||||
*/
|
||||
#ifdef XASH_USE_EVDEV
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <linux/input.h>
|
||||
#include <dirent.h>
|
||||
#include "common.h"
|
||||
#include "input.h"
|
||||
#include "client.h"
|
||||
#include "vgui_draw.h"
|
||||
|
||||
#define MAX_EVDEV_DEVICES 5
|
||||
|
||||
struct evdev_s
|
||||
{
|
||||
int initialized, devices;
|
||||
int fds[MAX_EVDEV_DEVICES];
|
||||
string paths[MAX_EVDEV_DEVICES];
|
||||
qboolean grab;
|
||||
float grabtime;
|
||||
float x, y;
|
||||
} evdev;
|
||||
|
||||
int KeycodeFromEvdev(int keycode, int value);
|
||||
|
||||
static void Evdev_CheckPermissions()
|
||||
{
|
||||
#ifdef __ANDROID__
|
||||
system( "su 0 chmod 664 /dev/input/event*" );
|
||||
#endif
|
||||
}
|
||||
|
||||
void Evdev_Setup( void )
|
||||
{
|
||||
if( evdev.initialized )
|
||||
return;
|
||||
#ifdef __ANDROID__
|
||||
system( "su 0 supolicy --live \"allow appdomain input_device dir { ioctl read getattr search open }\" \"allow appdomain input_device chr_file { ioctl read write getattr lock append open }\"" );
|
||||
system( "su 0 setenforce permissive" );
|
||||
#endif
|
||||
evdev.initialized = true;
|
||||
}
|
||||
|
||||
#define EV_HASBIT( x, y ) ( x[y / 32] & (1 << y % 32) )
|
||||
|
||||
void Evdev_Autodetect_f( void )
|
||||
{
|
||||
int i;
|
||||
DIR *dir;
|
||||
struct dirent *entry;
|
||||
|
||||
Evdev_Setup();
|
||||
|
||||
Evdev_CheckPermissions();
|
||||
|
||||
if( !( dir = opendir( "/dev/input" ) ) )
|
||||
return;
|
||||
|
||||
while( ( entry = readdir( dir ) ) )
|
||||
{
|
||||
int fd;
|
||||
string path;
|
||||
uint types[EV_MAX] = {0};
|
||||
uint codes[( KEY_MAX - 1 ) / 32 + 1] = {0};
|
||||
qboolean hasbtnmouse;
|
||||
|
||||
if( evdev.devices >= MAX_EVDEV_DEVICES )
|
||||
continue;
|
||||
|
||||
Q_snprintf( path, MAX_STRING, "/dev/input/%s", entry->d_name );
|
||||
|
||||
for( i = 0; i < evdev.devices; i++ )
|
||||
if( !Q_strncmp( evdev.paths[i], path, MAX_STRING ) )
|
||||
goto next;
|
||||
|
||||
if( Q_strncmp( entry->d_name, "event", 5 ) )
|
||||
continue;
|
||||
|
||||
fd = open( path, O_RDONLY | O_NONBLOCK );
|
||||
|
||||
if( fd == -1 )
|
||||
continue;
|
||||
|
||||
ioctl( fd, EVIOCGBIT( 0, EV_MAX ), types );
|
||||
|
||||
if( !EV_HASBIT( types, EV_KEY ) )
|
||||
goto close;
|
||||
|
||||
ioctl( fd, EVIOCGBIT( EV_KEY, KEY_MAX ), codes );
|
||||
|
||||
if( EV_HASBIT( codes, KEY_LEFTCTRL ) && EV_HASBIT( codes, KEY_SPACE ) )
|
||||
goto open;
|
||||
|
||||
if( !EV_HASBIT( codes, BTN_MOUSE ) )
|
||||
goto close;
|
||||
|
||||
if( EV_HASBIT( types, EV_REL ) )
|
||||
{
|
||||
Q_memset( codes, 0, sizeof( codes ) );
|
||||
ioctl( fd, EVIOCGBIT( EV_REL, KEY_MAX ), codes );
|
||||
|
||||
if( !EV_HASBIT( codes, REL_X ) )
|
||||
goto close;
|
||||
|
||||
if( !EV_HASBIT( codes, REL_Y ) )
|
||||
goto close;
|
||||
|
||||
if( !EV_HASBIT( codes, REL_WHEEL ) )
|
||||
goto close;
|
||||
|
||||
goto open;
|
||||
}
|
||||
goto close;
|
||||
open:
|
||||
Q_strncpy( evdev.paths[evdev.devices], path, MAX_STRING );
|
||||
evdev.fds[evdev.devices++] = fd;
|
||||
Msg( "Opened device %s\n", path );
|
||||
goto next;
|
||||
close:
|
||||
close( fd );
|
||||
next:
|
||||
continue;
|
||||
}
|
||||
closedir( dir );
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
===========
|
||||
Evdev_OpenDevice
|
||||
|
||||
For shitty systems that cannot provide relative mouse axes
|
||||
===========
|
||||
*/
|
||||
void Evdev_OpenDevice ( const char *path )
|
||||
{
|
||||
int ret, i;
|
||||
|
||||
if ( evdev.devices >= MAX_EVDEV_DEVICES )
|
||||
{
|
||||
Msg( "Only %d devices supported!\n", MAX_EVDEV_DEVICES );
|
||||
return;
|
||||
}
|
||||
|
||||
Evdev_Setup();
|
||||
|
||||
Evdev_CheckPermissions(); // use root to grant access to evdev
|
||||
|
||||
for( i = 0; i < evdev.devices; i++ )
|
||||
{
|
||||
if( !Q_strncmp( evdev.paths[i], path, MAX_STRING ) )
|
||||
{
|
||||
Msg( "device %s already open!\n", path );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ret = open( path, O_RDONLY | O_NONBLOCK );
|
||||
if( ret < 0 )
|
||||
{
|
||||
MsgDev( D_ERROR, "Could not open input device %s: %s\n", path, strerror( errno ) );
|
||||
return;
|
||||
}
|
||||
Msg( "Input device #%d: %s opened sucessfully\n", evdev.devices, path );
|
||||
evdev.fds[evdev.devices] = ret;
|
||||
Q_strncpy( evdev.paths[evdev.devices++], path, MAX_STRING );
|
||||
}
|
||||
|
||||
void Evdev_OpenDevice_f( void )
|
||||
{
|
||||
if( Cmd_Argc() < 2 )
|
||||
Msg( "Usage: evdev_opendevice <path>\n" );
|
||||
|
||||
Evdev_OpenDevice( Cmd_Argv( 1 ) );
|
||||
}
|
||||
|
||||
/*
|
||||
===========
|
||||
Evdev_CloseDevice_f
|
||||
===========
|
||||
*/
|
||||
void Evdev_CloseDevice_f ( void )
|
||||
{
|
||||
uint i;
|
||||
char *arg;
|
||||
|
||||
if( Cmd_Argc() < 2 )
|
||||
return;
|
||||
|
||||
arg = Cmd_Argv( 1 );
|
||||
|
||||
if( Q_isdigit( arg ) )
|
||||
i = Q_atoi( arg );
|
||||
else for( i = 0; i < evdev.devices; i++ )
|
||||
if( !Q_strncmp( evdev.paths[i], arg, MAX_STRING ) )
|
||||
break;
|
||||
|
||||
if( i >= evdev.devices )
|
||||
{
|
||||
Msg( "Device %s is not open\n", arg );
|
||||
return;
|
||||
}
|
||||
|
||||
close( evdev.fds[i] );
|
||||
evdev.devices--;
|
||||
Msg( "Device %s closed successfully\n", evdev.paths[i] );
|
||||
|
||||
for( ; i < evdev.devices; i++ )
|
||||
{
|
||||
Q_strncpy( evdev.paths[i], evdev.paths[i+1], MAX_STRING );
|
||||
evdev.fds[i] = evdev.fds[i+1];
|
||||
}
|
||||
}
|
||||
|
||||
void IN_EvdevFrame ()
|
||||
{
|
||||
int dx = 0, dy = 0, i;
|
||||
|
||||
for( i = 0; i < evdev.devices; i++ )
|
||||
{
|
||||
struct input_event ev;
|
||||
|
||||
while ( read( evdev.fds[i], &ev, 16) == 16 )
|
||||
{
|
||||
if ( ev.type == EV_REL )
|
||||
{
|
||||
switch ( ev.code )
|
||||
{
|
||||
case REL_X: dx += ev.value;
|
||||
break;
|
||||
|
||||
case REL_Y: dy += ev.value;
|
||||
break;
|
||||
|
||||
case REL_WHEEL:
|
||||
if( ev.value > 0)
|
||||
{
|
||||
Key_Event( K_MWHEELDOWN, 1 );
|
||||
Key_Event( K_MWHEELDOWN, 0 );
|
||||
}
|
||||
else
|
||||
{
|
||||
Key_Event( K_MWHEELUP, 1 );
|
||||
Key_Event( K_MWHEELUP, 0 );
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if ( ( ev.type == EV_KEY ) && cls.key_dest == key_game )
|
||||
{
|
||||
switch( ev.code )
|
||||
{
|
||||
case BTN_LEFT:
|
||||
Key_Event( K_MOUSE1, ev.value );
|
||||
break;
|
||||
case BTN_MIDDLE:
|
||||
Key_Event( K_MOUSE3, ev.value );
|
||||
break;
|
||||
case BTN_RIGHT:
|
||||
Key_Event( K_MOUSE2, ev.value );
|
||||
break;
|
||||
default:
|
||||
Key_Event ( KeycodeFromEvdev( ev.code, ev.value ) , ev.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( evdev.grab && evdev.grabtime <= host.realtime )
|
||||
{
|
||||
ioctl( evdev.fds[i], EVIOCGRAB, (void*) 1 );
|
||||
Key_ClearStates();
|
||||
}
|
||||
|
||||
if( m_ignore->integer )
|
||||
continue;
|
||||
|
||||
evdev.x += -dx * m_yaw->value;
|
||||
evdev.y += dy * m_pitch->value;
|
||||
}
|
||||
if( evdev.grabtime <= host.realtime )
|
||||
evdev.grab = false;
|
||||
}
|
||||
|
||||
void Evdev_SetGrab( qboolean grab )
|
||||
{
|
||||
int i;
|
||||
|
||||
if( grab )
|
||||
{
|
||||
Key_Event( K_ESCAPE, 0 ); //Do not leave ESC down
|
||||
evdev.grabtime = host.realtime + 0.5;
|
||||
Key_ClearStates();
|
||||
}
|
||||
else
|
||||
{
|
||||
for( i = 0; i < evdev.devices; i++ )
|
||||
ioctl( evdev.fds[i], EVIOCGRAB, (void*) 0 );
|
||||
}
|
||||
evdev.grab = grab;
|
||||
}
|
||||
|
||||
void IN_EvdevMove( float *yaw, float *pitch )
|
||||
{
|
||||
*yaw += evdev.x;
|
||||
*pitch += evdev.y;
|
||||
evdev.x = evdev.y = 0.0f;
|
||||
}
|
||||
|
||||
void Evdev_Init( void )
|
||||
{
|
||||
Cmd_AddCommand ("evdev_open", Evdev_OpenDevice_f, "Open event device");
|
||||
Cmd_AddCommand ("evdev_close", Evdev_CloseDevice_f, "Close event device");
|
||||
Cmd_AddCommand ("evdev_autodetect", Evdev_Autodetect_f, "Automaticly open mouses and keyboards");
|
||||
}
|
||||
|
||||
void Evdev_Shutdown( void )
|
||||
{
|
||||
Cmd_RemoveCommand( "evdev_open" );
|
||||
Cmd_RemoveCommand( "evdev_close" );
|
||||
Cmd_RemoveCommand( "evdev_autodetect" );
|
||||
}
|
||||
|
||||
#endif // XASH_USE_EVDEV
|
473
engine/client/in_joy.c
Normal file
473
engine/client/in_joy.c
Normal file
@ -0,0 +1,473 @@
|
||||
/*
|
||||
joyinput.c - joystick common input code
|
||||
|
||||
Copyright (C) 2016 a1batross
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef XASH_DEDICATED
|
||||
|
||||
#include "common.h"
|
||||
#include "input.h"
|
||||
#include "keydefs.h"
|
||||
#include "joyinput.h"
|
||||
#include "client.h"
|
||||
#include "gl_local.h"
|
||||
|
||||
#if defined(XASH_SDL)
|
||||
#include "platform/sdl/events.h"
|
||||
#endif
|
||||
|
||||
#ifndef SHRT_MAX
|
||||
#define SHRT_MAX 0x7FFF
|
||||
#endif
|
||||
|
||||
typedef enum engineAxis_e
|
||||
{
|
||||
JOY_AXIS_SIDE = 0,
|
||||
JOY_AXIS_FWD,
|
||||
JOY_AXIS_PITCH,
|
||||
JOY_AXIS_YAW,
|
||||
JOY_AXIS_RT,
|
||||
JOY_AXIS_LT,
|
||||
JOY_AXIS_NULL
|
||||
} engineAxis_t;
|
||||
|
||||
#define MAX_AXES JOY_AXIS_NULL
|
||||
|
||||
#define JOY_SIMULATED_HAT_ID ( -1 )
|
||||
|
||||
// index - axis num come from event
|
||||
// value - inner axis
|
||||
static engineAxis_t joyaxesmap[MAX_AXES] =
|
||||
{
|
||||
JOY_AXIS_SIDE, // left stick, x
|
||||
JOY_AXIS_FWD, // left stick, y
|
||||
JOY_AXIS_PITCH, // right stick, y
|
||||
JOY_AXIS_YAW, // right stick, x
|
||||
JOY_AXIS_RT, // right trigger
|
||||
JOY_AXIS_LT // left trigger
|
||||
};
|
||||
|
||||
static struct joy_axis_s
|
||||
{
|
||||
short val;
|
||||
short prevval;
|
||||
} joyaxis[MAX_AXES] = { 0 };
|
||||
static qboolean initialized = false, forcedisable = false;
|
||||
static convar_t *joy_enable;
|
||||
static byte currentbinding; // add posibility to remap keys, to place it in joykeys[]
|
||||
|
||||
float IN_TouchDrawText( float x1, float y1, float x2, float y2, const char *s, byte *color, float size );
|
||||
float IN_TouchDrawCharacter( float x, float y, int number, float size );
|
||||
|
||||
convar_t *joy_pitch;
|
||||
convar_t *joy_yaw;
|
||||
convar_t *joy_forward;
|
||||
convar_t *joy_side;
|
||||
convar_t *joy_found;
|
||||
convar_t *joy_index;
|
||||
convar_t *joy_lt_threshold;
|
||||
convar_t *joy_rt_threshold;
|
||||
convar_t *joy_side_deadzone;
|
||||
convar_t *joy_forward_deadzone;
|
||||
convar_t *joy_side_key_threshold;
|
||||
convar_t *joy_forward_key_threshold;
|
||||
convar_t *joy_pitch_deadzone;
|
||||
convar_t *joy_yaw_deadzone;
|
||||
convar_t *joy_axis_binding;
|
||||
|
||||
/*
|
||||
============
|
||||
Joy_IsActive
|
||||
============
|
||||
*/
|
||||
qboolean Joy_IsActive( void )
|
||||
{
|
||||
return !forcedisable && initialized;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
Joy_HatMotionEvent
|
||||
|
||||
DPad events
|
||||
============
|
||||
*/
|
||||
void Joy_HatMotionEvent( int id, byte hat, byte value )
|
||||
{
|
||||
struct
|
||||
{
|
||||
int mask;
|
||||
int key;
|
||||
} keys[] =
|
||||
{
|
||||
{ JOY_HAT_UP, K_UPARROW },
|
||||
{ JOY_HAT_DOWN, K_DOWNARROW },
|
||||
{ JOY_HAT_LEFT, K_LEFTARROW },
|
||||
{ JOY_HAT_RIGHT, K_RIGHTARROW },
|
||||
};
|
||||
int i;
|
||||
|
||||
if( !initialized )
|
||||
return;
|
||||
|
||||
for( i = 0; i < ARRAYSIZE( keys ); i++ )
|
||||
{
|
||||
if( value & keys[i].mask )
|
||||
{
|
||||
if( !Key_IsDown( keys[i].key ))
|
||||
Key_Event( keys[i].key, true );
|
||||
}
|
||||
else
|
||||
{
|
||||
if( Key_IsDown( keys[i].key ))
|
||||
Key_Event( keys[i].key, false );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
Joy_ProcessTrigger
|
||||
=============
|
||||
*/
|
||||
void Joy_ProcessTrigger( const engineAxis_t engineAxis, short value )
|
||||
{
|
||||
int trigButton = 0, trigThreshold = 0;
|
||||
|
||||
switch( engineAxis )
|
||||
{
|
||||
case JOY_AXIS_RT:
|
||||
trigButton = K_JOY2;
|
||||
trigThreshold = joy_rt_threshold->integer;
|
||||
break;
|
||||
case JOY_AXIS_LT:
|
||||
trigButton = K_JOY1;
|
||||
trigThreshold = joy_lt_threshold->integer;
|
||||
break;
|
||||
default:
|
||||
MsgDev( D_ERROR, "Joy_ProcessTrigger: invalid axis = %i", engineAxis );
|
||||
break;
|
||||
}
|
||||
|
||||
// update axis values
|
||||
joyaxis[engineAxis].prevval = joyaxis[engineAxis].val;
|
||||
joyaxis[engineAxis].val = value;
|
||||
|
||||
if( joyaxis[engineAxis].val > trigThreshold &&
|
||||
joyaxis[engineAxis].prevval <= trigThreshold ) // ignore random press
|
||||
{
|
||||
Key_Event( trigButton, true );
|
||||
}
|
||||
else if( joyaxis[engineAxis].val < trigThreshold &&
|
||||
joyaxis[engineAxis].prevval >= trigThreshold ) // we're unpressing (inverted)
|
||||
{
|
||||
Key_Event( trigButton, false );
|
||||
}
|
||||
}
|
||||
|
||||
int Joy_GetHatValueForAxis( const engineAxis_t engineAxis )
|
||||
{
|
||||
int threshold, negative, positive;
|
||||
|
||||
switch( engineAxis )
|
||||
{
|
||||
case JOY_AXIS_SIDE:
|
||||
threshold = joy_side_key_threshold->integer;
|
||||
negative = JOY_HAT_LEFT;
|
||||
positive = JOY_HAT_RIGHT;
|
||||
break;
|
||||
case JOY_AXIS_FWD:
|
||||
threshold = joy_side_key_threshold->integer;
|
||||
negative = JOY_HAT_UP;
|
||||
positive = JOY_HAT_DOWN;
|
||||
break;
|
||||
default:
|
||||
ASSERT( false ); // only fwd/side axes can emit key events
|
||||
return 0;
|
||||
}
|
||||
|
||||
// similar code in Joy_ProcessTrigger
|
||||
if( joyaxis[engineAxis].val > threshold &&
|
||||
joyaxis[engineAxis].prevval <= threshold ) // ignore random press
|
||||
{
|
||||
return positive;
|
||||
}
|
||||
if( joyaxis[engineAxis].val < -threshold &&
|
||||
joyaxis[engineAxis].prevval >= -threshold ) // we're unpressing (inverted)
|
||||
{
|
||||
return negative;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
Joy_ProcessStick
|
||||
=============
|
||||
*/
|
||||
void Joy_ProcessStick( const engineAxis_t engineAxis, short value )
|
||||
{
|
||||
int deadzone = 0;
|
||||
|
||||
switch( engineAxis )
|
||||
{
|
||||
case JOY_AXIS_FWD: deadzone = joy_forward_deadzone->integer; break;
|
||||
case JOY_AXIS_SIDE: deadzone = joy_side_deadzone->integer; break;
|
||||
case JOY_AXIS_PITCH: deadzone = joy_pitch_deadzone->integer; break;
|
||||
case JOY_AXIS_YAW: deadzone = joy_yaw_deadzone->integer; break;
|
||||
default:
|
||||
MsgDev( D_ERROR, "Joy_ProcessStick: invalid axis = %i", engineAxis );
|
||||
break;
|
||||
}
|
||||
|
||||
if( value < deadzone && value > -deadzone )
|
||||
value = 0; // caught new event in deadzone, fill it with zero(no motion)
|
||||
|
||||
// update axis values
|
||||
joyaxis[engineAxis].prevval = joyaxis[engineAxis].val;
|
||||
joyaxis[engineAxis].val = value;
|
||||
|
||||
// fwd/side axis simulate hat movement
|
||||
if( ( engineAxis == JOY_AXIS_SIDE || engineAxis == JOY_AXIS_FWD ) &&
|
||||
( CL_IsInMenu() || CL_IsInConsole() ) )
|
||||
{
|
||||
int val = 0;
|
||||
|
||||
val |= Joy_GetHatValueForAxis( JOY_AXIS_SIDE );
|
||||
val |= Joy_GetHatValueForAxis( JOY_AXIS_FWD );
|
||||
|
||||
Joy_HatMotionEvent( JOY_SIMULATED_HAT_ID, 0, val );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
Joy_AxisMotionEvent
|
||||
|
||||
Axis events
|
||||
=============
|
||||
*/
|
||||
void Joy_AxisMotionEvent( int id, byte axis, short value )
|
||||
{
|
||||
byte engineAxis;
|
||||
|
||||
if( !initialized )
|
||||
return;
|
||||
|
||||
if( axis >= MAX_AXES )
|
||||
{
|
||||
MsgDev( D_INFO, "Only 6 axes is supported\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
engineAxis = joyaxesmap[axis]; // convert to engine inner axis control
|
||||
|
||||
if( engineAxis == JOY_AXIS_NULL )
|
||||
return;
|
||||
|
||||
if( value == joyaxis[engineAxis].val )
|
||||
return; // it is not an update
|
||||
|
||||
if( engineAxis >= JOY_AXIS_RT )
|
||||
Joy_ProcessTrigger( engineAxis, value );
|
||||
else
|
||||
Joy_ProcessStick( engineAxis, value );
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
Joy_BallMotionEvent
|
||||
|
||||
Trackball events. UNDONE
|
||||
=============
|
||||
*/
|
||||
void Joy_BallMotionEvent( int id, byte ball, short xrel, short yrel )
|
||||
{
|
||||
//if( !initialized )
|
||||
// return;
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
Joy_ButtonEvent
|
||||
|
||||
Button events
|
||||
=============
|
||||
*/
|
||||
void Joy_ButtonEvent( int id, byte button, byte down )
|
||||
{
|
||||
if( !initialized )
|
||||
return;
|
||||
|
||||
// generic game button code.
|
||||
if( button > 32 )
|
||||
{
|
||||
int origbutton = button;
|
||||
button = ( button & 31 ) + K_AUX1;
|
||||
|
||||
MsgDev( D_INFO, "Only 32 joybuttons is supported, converting %i button ID to %s\n", origbutton, Key_KeynumToString( button ) );
|
||||
}
|
||||
else button += K_AUX1;
|
||||
|
||||
Key_Event( button, down );
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
Joy_RemoveEvent
|
||||
|
||||
Called when joystick is removed. For future expansion
|
||||
=============
|
||||
*/
|
||||
void Joy_RemoveEvent( int id )
|
||||
{
|
||||
if( !forcedisable && initialized && joy_found->integer )
|
||||
Cvar_SetFloat("joy_found", joy_found->value - 1.0f);
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
Joy_RemoveEvent
|
||||
|
||||
Called when joystick is removed. For future expansion
|
||||
=============
|
||||
*/
|
||||
void Joy_AddEvent( int id )
|
||||
{
|
||||
if( forcedisable )
|
||||
return;
|
||||
|
||||
initialized = true;
|
||||
|
||||
Cvar_SetFloat("joy_found", joy_found->value + 1.0f);
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
Joy_FinalizeMove
|
||||
|
||||
Append movement from axis. Called everyframe
|
||||
=============
|
||||
*/
|
||||
void Joy_FinalizeMove( float *fw, float *side, float *dpitch, float *dyaw )
|
||||
{
|
||||
if( !initialized || !joy_enable->integer )
|
||||
return;
|
||||
|
||||
if( joy_axis_binding->modified )
|
||||
{
|
||||
char bind[7] = { 0 }; // fill it with zeros
|
||||
size_t i;
|
||||
Q_strncpy( bind, joy_axis_binding->string, sizeof(bind) );
|
||||
|
||||
for( i = 0; i < sizeof(bind); i++ )
|
||||
{
|
||||
switch( bind[i] )
|
||||
{
|
||||
case 's': joyaxesmap[i] = JOY_AXIS_SIDE; break;
|
||||
case 'f': joyaxesmap[i] = JOY_AXIS_FWD; break;
|
||||
case 'y': joyaxesmap[i] = JOY_AXIS_YAW; break;
|
||||
case 'p': joyaxesmap[i] = JOY_AXIS_PITCH; break;
|
||||
case 'r': joyaxesmap[i] = JOY_AXIS_RT; break;
|
||||
case 'l': joyaxesmap[i] = JOY_AXIS_LT; break;
|
||||
default : joyaxesmap[i] = JOY_AXIS_NULL; break;
|
||||
}
|
||||
}
|
||||
joy_axis_binding->modified = false;
|
||||
}
|
||||
|
||||
*fw -= joy_forward->value * (float)joyaxis[JOY_AXIS_FWD ].val/(float)SHRT_MAX; // must be form -1.0 to 1.0
|
||||
*side += joy_side->value * (float)joyaxis[JOY_AXIS_SIDE].val/(float)SHRT_MAX;
|
||||
#if !defined(XASH_SDL)
|
||||
*dpitch += joy_pitch->value * (float)joyaxis[JOY_AXIS_PITCH].val/(float)SHRT_MAX * host.realframetime; // abs axis rotate is frametime related
|
||||
*dyaw -= joy_yaw->value * (float)joyaxis[JOY_AXIS_YAW ].val/(float)SHRT_MAX * host.realframetime;
|
||||
#else
|
||||
// HACKHACK: SDL have inverted look axis.
|
||||
*dpitch -= joy_pitch->value * (float)joyaxis[JOY_AXIS_PITCH].val/(float)SHRT_MAX * host.realframetime;
|
||||
*dyaw += joy_yaw->value * (float)joyaxis[JOY_AXIS_YAW ].val/(float)SHRT_MAX * host.realframetime;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
Joy_Init
|
||||
|
||||
Main init procedure
|
||||
=============
|
||||
*/
|
||||
void Joy_Init( void )
|
||||
{
|
||||
joy_pitch = Cvar_Get( "joy_pitch", "100.0", CVAR_ARCHIVE, "joystick pitch sensitivity" );
|
||||
joy_yaw = Cvar_Get( "joy_yaw", "100.0", CVAR_ARCHIVE, "joystick yaw sensitivity" );
|
||||
joy_side = Cvar_Get( "joy_side", "1.0", CVAR_ARCHIVE, "joystick side sensitivity. Values from -1.0 to 1.0" );
|
||||
joy_forward = Cvar_Get( "joy_forward", "1.0", CVAR_ARCHIVE, "joystick forward sensitivity. Values from -1.0 to 1.0" );
|
||||
|
||||
joy_lt_threshold = Cvar_Get( "joy_lt_threshold", "-16384", CVAR_ARCHIVE, "left trigger threshold. Value from -32768 to 32767");
|
||||
joy_rt_threshold = Cvar_Get( "joy_rt_threshold", "-16384", CVAR_ARCHIVE, "right trigger threshold. Value from -32768 to 32767" );
|
||||
|
||||
// emit a key event at 75% axis move
|
||||
joy_side_key_threshold = Cvar_Get( "joy_side_key_threshold", "24576", CVAR_ARCHIVE, "side axis key event emit threshold. Value from 0 to 32767" );
|
||||
joy_forward_key_threshold = Cvar_Get( "joy_forward_key_threshold", "24576", CVAR_ARCHIVE, "forward axis key event emit threshold. Value from 0 to 32767");
|
||||
|
||||
// by default, we rely on deadzone detection come from system, but some glitchy devices report false deadzones
|
||||
joy_side_deadzone = Cvar_Get( "joy_side_deadzone", "0", CVAR_ARCHIVE, "side axis deadzone. Value from 0 to 32767" );
|
||||
joy_forward_deadzone = Cvar_Get( "joy_forward_deadzone", "0", CVAR_ARCHIVE, "forward axis deadzone. Value from 0 to 32767");
|
||||
joy_pitch_deadzone = Cvar_Get( "joy_pitch_deadzone", "0", CVAR_ARCHIVE, "pitch axis deadzone. Value from 0 to 32767");
|
||||
joy_yaw_deadzone = Cvar_Get( "joy_yaw_deadzone", "0", CVAR_ARCHIVE, "yaw axis deadzone. Value from 0 to 32767" );
|
||||
|
||||
joy_axis_binding = Cvar_Get( "joy_axis_binding", "sfpyrl", CVAR_ARCHIVE, "axis hardware id to engine inner axis binding, "
|
||||
"s - side, f - forward, y - yaw, p - pitch, r - left trigger, l - right trigger" );
|
||||
joy_found = Cvar_Get( "joy_found", "0", CVAR_READ_ONLY, "total num of connected joysticks" );
|
||||
// we doesn't loaded config.cfg yet, so this cvar is not archive.
|
||||
// change by +set joy_index in cmdline
|
||||
joy_index = Cvar_Get( "joy_index", "0", CVAR_READ_ONLY, "current active joystick" );
|
||||
|
||||
joy_enable = Cvar_Get( "joy_enable", "1", CVAR_ARCHIVE, "enable joystick" );
|
||||
|
||||
if( Sys_CheckParm("-nojoy" ) )
|
||||
{
|
||||
forcedisable = true;
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined(XASH_SDL)
|
||||
// SDL can tell us about connected joysticks
|
||||
Cvar_SetFloat( "joy_found", SDLash_JoyInit( joy_index->integer ) );
|
||||
#elif defined(ANDROID)
|
||||
// Initalized after first Joy_AddEvent
|
||||
#else
|
||||
#warning "Any platform must implement platform-dependent JoyInit, start event system. Otherwise no joystick support"
|
||||
#endif
|
||||
|
||||
if( joy_found->integer > 0 )
|
||||
initialized = true;
|
||||
else
|
||||
initialized = false;
|
||||
}
|
||||
|
||||
/*
|
||||
===========
|
||||
Joy_Shutdown
|
||||
|
||||
Shutdown joystick code
|
||||
===========
|
||||
*/
|
||||
void Joy_Shutdown( void )
|
||||
{
|
||||
Cvar_SetFloat( "joy_found", 0 );
|
||||
|
||||
initialized = false;
|
||||
}
|
||||
|
||||
#endif // XASH_DEDICATED
|
1768
engine/client/in_touch.c
Normal file
1768
engine/client/in_touch.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -17,100 +17,38 @@ GNU General Public License for more details.
|
||||
#include "input.h"
|
||||
#include "client.h"
|
||||
#include "vgui_draw.h"
|
||||
#include "gl_local.h"
|
||||
|
||||
#define PRINTSCREEN_ID 1
|
||||
#define WND_HEADSIZE wnd_caption // some offset
|
||||
#define WND_BORDER 3 // sentinel border in pixels
|
||||
#ifdef XASH_SDL
|
||||
#include <SDL.h>
|
||||
#endif
|
||||
|
||||
HICON in_mousecursor;
|
||||
#ifdef _WIN32
|
||||
#include "windows.h"
|
||||
#endif
|
||||
|
||||
void* in_mousecursor;
|
||||
qboolean in_mouseactive; // false when not focus app
|
||||
qboolean in_restore_spi;
|
||||
qboolean in_mouseinitialized;
|
||||
int in_mouse_oldbuttonstate;
|
||||
qboolean in_mouse_suspended;
|
||||
POINT in_lastvalidpos;
|
||||
qboolean in_mouse_savedpos;
|
||||
int in_mouse_buttons;
|
||||
RECT window_rect, real_rect;
|
||||
POINT in_lastvalidpos;
|
||||
uint in_mouse_wheel;
|
||||
int wnd_caption;
|
||||
|
||||
static byte scan_to_key[128] =
|
||||
{
|
||||
0,27,'1','2','3','4','5','6','7','8','9','0','-','=',K_BACKSPACE,9,
|
||||
'q','w','e','r','t','y','u','i','o','p','[',']', 13 , K_CTRL,
|
||||
'a','s','d','f','g','h','j','k','l',';','\'','`',
|
||||
K_SHIFT,'\\','z','x','c','v','b','n','m',',','.','/',K_SHIFT,
|
||||
'*',K_ALT,' ',K_CAPSLOCK,
|
||||
K_F1,K_F2,K_F3,K_F4,K_F5,K_F6,K_F7,K_F8,K_F9,K_F10,
|
||||
K_PAUSE,0,K_HOME,K_UPARROW,K_PGUP,K_KP_MINUS,K_LEFTARROW,K_KP_5,
|
||||
K_RIGHTARROW,K_KP_PLUS,K_END,K_DOWNARROW,K_PGDN,K_INS,K_DEL,
|
||||
0,0,0,K_F11,K_F12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
};
|
||||
|
||||
// extra mouse buttons
|
||||
static int mouse_buttons[] =
|
||||
static struct inputstate_s
|
||||
{
|
||||
MK_LBUTTON,
|
||||
MK_RBUTTON,
|
||||
MK_MBUTTON,
|
||||
MK_XBUTTON1,
|
||||
MK_XBUTTON2,
|
||||
MK_XBUTTON3,
|
||||
MK_XBUTTON4,
|
||||
MK_XBUTTON5
|
||||
};
|
||||
|
||||
/*
|
||||
=======
|
||||
Host_MapKey
|
||||
float lastpitch, lastyaw;
|
||||
} inputstate;
|
||||
|
||||
Map from windows to engine keynums
|
||||
=======
|
||||
*/
|
||||
static int Host_MapKey( int key )
|
||||
{
|
||||
int result, modified;
|
||||
qboolean is_extended = false;
|
||||
extern convar_t *vid_fullscreen;
|
||||
convar_t *m_enginemouse;
|
||||
convar_t *m_pitch;
|
||||
convar_t *m_yaw;
|
||||
|
||||
modified = ( key >> 16 ) & 255;
|
||||
if( modified > 127 ) return 0;
|
||||
|
||||
if( key & ( 1 << 24 ))
|
||||
is_extended = true;
|
||||
|
||||
result = scan_to_key[modified];
|
||||
|
||||
if( !is_extended )
|
||||
{
|
||||
switch( result )
|
||||
{
|
||||
case K_HOME: return K_KP_HOME;
|
||||
case K_UPARROW: return K_KP_UPARROW;
|
||||
case K_PGUP: return K_KP_PGUP;
|
||||
case K_LEFTARROW: return K_KP_LEFTARROW;
|
||||
case K_RIGHTARROW: return K_KP_RIGHTARROW;
|
||||
case K_END: return K_KP_END;
|
||||
case K_DOWNARROW: return K_KP_DOWNARROW;
|
||||
case K_PGDN: return K_KP_PGDN;
|
||||
case K_INS: return K_KP_INS;
|
||||
case K_DEL: return K_KP_DEL;
|
||||
default: return result;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch( result )
|
||||
{
|
||||
case K_PAUSE: return K_KP_NUMLOCK;
|
||||
case 0x0D: return K_KP_ENTER;
|
||||
case 0x2F: return K_KP_SLASH;
|
||||
case 0xAF: return K_KP_PLUS;
|
||||
default: return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
convar_t *m_enginesens;
|
||||
convar_t *m_ignore;
|
||||
convar_t *cl_forwardspeed;
|
||||
convar_t *cl_sidespeed;
|
||||
convar_t *cl_backspeed;
|
||||
convar_t *look_filter;
|
||||
|
||||
/*
|
||||
===========
|
||||
@ -119,40 +57,28 @@ IN_StartupMouse
|
||||
*/
|
||||
void IN_StartupMouse( void )
|
||||
{
|
||||
if( host.type == HOST_DEDICATED ) return;
|
||||
if( Sys_CheckParm( "-nomouse" )) return;
|
||||
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_mouse_buttons = 8;
|
||||
in_mouseinitialized = true;
|
||||
in_mouse_wheel = RegisterWindowMessage( "MSWHEEL_ROLLMSG" );
|
||||
}
|
||||
|
||||
static qboolean IN_CursorInRect( void )
|
||||
{
|
||||
POINT curpos;
|
||||
|
||||
if( !in_mouseinitialized || !in_mouseactive )
|
||||
return false;
|
||||
|
||||
// find mouse movement
|
||||
GetCursorPos( &curpos );
|
||||
|
||||
if( curpos.x < real_rect.left + WND_BORDER )
|
||||
return false;
|
||||
if( curpos.x > real_rect.right - WND_BORDER * 3 )
|
||||
return false;
|
||||
if( curpos.y < real_rect.top + WND_HEADSIZE + WND_BORDER )
|
||||
return false;
|
||||
if( curpos.y > real_rect.bottom - WND_BORDER * 3 )
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void IN_ActivateCursor( void )
|
||||
{
|
||||
if( cls.key_dest == key_menu )
|
||||
{
|
||||
SetCursor( in_mousecursor );
|
||||
#ifdef XASH_SDL
|
||||
SDL_SetCursor( in_mousecursor );
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@ -175,8 +101,10 @@ void IN_MouseSavePos( void )
|
||||
if( !in_mouseactive )
|
||||
return;
|
||||
|
||||
GetCursorPos( &in_lastvalidpos );
|
||||
#ifdef XASH_SDL
|
||||
SDL_GetMouseState( &in_lastvalidpos.x, &in_lastvalidpos.y );
|
||||
in_mouse_savedpos = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
@ -191,7 +119,10 @@ void IN_MouseRestorePos( void )
|
||||
if( !in_mouse_savedpos )
|
||||
return;
|
||||
|
||||
SetCursorPos( in_lastvalidpos.x, in_lastvalidpos.y );
|
||||
#ifdef XASH_SDL
|
||||
SDL_WarpMouseInWindow( host.hWnd, in_lastvalidpos.x, in_lastvalidpos.y );
|
||||
#endif
|
||||
|
||||
in_mouse_savedpos = false;
|
||||
}
|
||||
|
||||
@ -213,16 +144,46 @@ void IN_ToggleClientMouse( int newstate, int oldstate )
|
||||
else if( newstate == key_game )
|
||||
{
|
||||
// reset mouse pos, so cancel effect in game
|
||||
SetCursorPos( host.window_center_x, host.window_center_y );
|
||||
clgame.dllFuncs.IN_ActivateMouse();
|
||||
#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 && ( !CL_IsBackgroundMap() || CL_IsBackgroundDemo( )))
|
||||
if( ( newstate == key_menu || newstate == key_console || newstate == key_message ) && ( !CL_IsBackgroundMap() || CL_IsBackgroundDemo( )))
|
||||
{
|
||||
in_mouseactive = false;
|
||||
ClipCursor( NULL );
|
||||
ReleaseCapture();
|
||||
while( ShowCursor( true ) < 0 );
|
||||
#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
|
||||
}
|
||||
}
|
||||
|
||||
@ -254,16 +215,16 @@ void IN_ActivateMouse( qboolean force )
|
||||
{
|
||||
if( in_mouse_suspended )
|
||||
{
|
||||
ClipCursor( NULL );
|
||||
ReleaseCapture();
|
||||
while( ShowCursor( true ) < 0 );
|
||||
#ifdef XASH_SDL
|
||||
SDL_ShowCursor( false );
|
||||
#endif
|
||||
UI_ShowCursor( false );
|
||||
}
|
||||
}
|
||||
|
||||
oldstate = in_mouse_suspended;
|
||||
|
||||
if( in_mouse_suspended && IN_CursorInRect( ))
|
||||
if( in_mouse_suspended )
|
||||
{
|
||||
in_mouse_suspended = false;
|
||||
in_mouseactive = false; // re-initialize mouse
|
||||
@ -279,24 +240,10 @@ void IN_ActivateMouse( qboolean force )
|
||||
if( cls.key_dest == key_game )
|
||||
{
|
||||
clgame.dllFuncs.IN_ActivateMouse();
|
||||
#ifdef XASH_SDL
|
||||
SDL_GetRelativeMouseState( 0, 0 ); // Reset mouse position
|
||||
#endif
|
||||
}
|
||||
|
||||
width = GetSystemMetrics( SM_CXSCREEN );
|
||||
height = GetSystemMetrics( SM_CYSCREEN );
|
||||
|
||||
GetWindowRect( host.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;
|
||||
|
||||
host.window_center_x = (window_rect.right + window_rect.left) / 2;
|
||||
host.window_center_y = (window_rect.top + window_rect.bottom) / 2;
|
||||
SetCursorPos( host.window_center_x, host.window_center_y );
|
||||
|
||||
SetCapture( host.hWnd );
|
||||
ClipCursor( &window_rect );
|
||||
while( ShowCursor( false ) >= 0 );
|
||||
}
|
||||
|
||||
/*
|
||||
@ -317,9 +264,9 @@ void IN_DeactivateMouse( void )
|
||||
}
|
||||
|
||||
in_mouseactive = false;
|
||||
ClipCursor( NULL );
|
||||
ReleaseCapture();
|
||||
while( ShowCursor( true ) < 0 );
|
||||
#ifdef XASH_SDL
|
||||
SDL_SetWindowGrab( host.hWnd, SDL_FALSE );
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
@ -335,11 +282,19 @@ void IN_MouseMove( void )
|
||||
return;
|
||||
|
||||
// find mouse movement
|
||||
GetCursorPos( ¤t_pos );
|
||||
ScreenToClient( host.hWnd, ¤t_pos );
|
||||
#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 );
|
||||
|
||||
@ -351,34 +306,62 @@ void IN_MouseMove( void )
|
||||
IN_MouseEvent
|
||||
===========
|
||||
*/
|
||||
void IN_MouseEvent( int mstate )
|
||||
void IN_MouseEvent( void )
|
||||
{
|
||||
int i;
|
||||
|
||||
if( !in_mouseinitialized || !in_mouseactive )
|
||||
return;
|
||||
|
||||
if( m_ignore->value )
|
||||
return;
|
||||
|
||||
if( cls.key_dest == key_game )
|
||||
{
|
||||
clgame.dllFuncs.IN_MouseEvent( mstate );
|
||||
#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;
|
||||
}
|
||||
|
||||
// perform button actions
|
||||
for( i = 0; i < in_mouse_buttons; i++ )
|
||||
else
|
||||
{
|
||||
if( FBitSet( mstate, BIT( i )) && !FBitSet( in_mouse_oldbuttonstate, BIT( i )))
|
||||
{
|
||||
Key_Event( K_MOUSE1 + i, true );
|
||||
}
|
||||
|
||||
if( !FBitSet( mstate, BIT( i )) && FBitSet( in_mouse_oldbuttonstate, BIT( i )))
|
||||
{
|
||||
Key_Event( K_MOUSE1 + i, false );
|
||||
}
|
||||
}
|
||||
|
||||
in_mouse_oldbuttonstate = mstate;
|
||||
#if defined(XASH_SDL) && !defined(_WIN32)
|
||||
SDL_SetRelativeMouseMode( SDL_FALSE );
|
||||
SDL_ShowCursor( SDL_TRUE );
|
||||
#endif
|
||||
IN_MouseMove();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -389,6 +372,10 @@ IN_Shutdown
|
||||
void IN_Shutdown( void )
|
||||
{
|
||||
IN_DeactivateMouse( );
|
||||
|
||||
#ifdef XASH_USE_EVDEV
|
||||
Evdev_Shutdown();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@ -399,7 +386,171 @@ IN_Init
|
||||
*/
|
||||
void IN_Init( void )
|
||||
{
|
||||
IN_StartupMouse( );
|
||||
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 );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -412,9 +563,57 @@ 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;
|
||||
|
||||
|
@ -26,23 +26,13 @@ INPUT
|
||||
|
||||
#include "keydefs.h"
|
||||
|
||||
#define WHEEL_DELTA 120 // Default value for rolling one notch
|
||||
#define WM_MOUSEWHEEL ( WM_MOUSELAST + 1 )// message that will be supported by the OS
|
||||
#define MK_XBUTTON1 0x0020
|
||||
#define MK_XBUTTON2 0x0040
|
||||
#define MK_XBUTTON3 0x0080
|
||||
#define MK_XBUTTON4 0x0100
|
||||
#define MK_XBUTTON5 0x0200
|
||||
#define WM_XBUTTONUP 0x020C
|
||||
#define WM_XBUTTONDOWN 0x020B
|
||||
|
||||
//
|
||||
// input.c
|
||||
//
|
||||
void IN_Init( void );
|
||||
void Host_InputFrame( void );
|
||||
void IN_Shutdown( void );
|
||||
void IN_MouseEvent( int mstate );
|
||||
void IN_MouseEvent( void );
|
||||
void IN_ActivateMouse( qboolean force );
|
||||
void IN_DeactivateMouse( void );
|
||||
void IN_MouseSavePos( void );
|
||||
@ -50,4 +40,73 @@ void IN_MouseRestorePos( void );
|
||||
void IN_ToggleClientMouse( int newstate, int oldstate );
|
||||
void IN_SetCursor( void *hCursor );
|
||||
|
||||
//
|
||||
// in_touch.c
|
||||
//
|
||||
typedef enum
|
||||
{
|
||||
event_down = 0,
|
||||
event_up,
|
||||
event_motion
|
||||
} touchEventType;
|
||||
|
||||
extern convar_t *touch_enable;
|
||||
|
||||
void IN_TouchDraw( void );
|
||||
void IN_TouchEditClear( void );
|
||||
void IN_TouchSetClientOnly( qboolean state );
|
||||
void IN_TouchRemoveButton( const char *name );
|
||||
void IN_TouchHideButtons( const char *name, qboolean hide );
|
||||
//void IN_TouchSetCommand( const char *name, const char *command );
|
||||
//void IN_TouchSetTexture( const char *name, const char *texture );
|
||||
//void IN_TouchSetColor( const char *name, byte *color );
|
||||
void IN_TouchAddClientButton( const char *name, const char *texture, const char *command, float x1, float y1, float x2, float y2, byte *color, int round, float aspect, int flags );
|
||||
void IN_TouchAddDefaultButton( const char *name, const char *texturefile, const char *command, float x1, float y1, float x2, float y2, byte *color, int round, float aspect, int flags );
|
||||
void IN_TouchInitConfig( void );
|
||||
void IN_TouchWriteConfig( void );
|
||||
void IN_TouchInit( void );
|
||||
void IN_TouchShutdown( void );
|
||||
void IN_TouchMove( float * forward, float *side, float *yaw, float *pitch );
|
||||
void IN_TouchResetDefaultButtons( void );
|
||||
int IN_TouchEvent( touchEventType type, int fingerID, float x, float y, float dx, float dy );
|
||||
void IN_TouchKeyEvent( int key, int down );
|
||||
|
||||
//
|
||||
// in_joy.c
|
||||
//
|
||||
enum
|
||||
{
|
||||
JOY_HAT_CENTERED = 0,
|
||||
JOY_HAT_UP = BIT(0),
|
||||
JOY_HAT_RIGHT = BIT(1),
|
||||
JOY_HAT_DOWN = BIT(2),
|
||||
JOY_HAT_LEFT = BIT(3),
|
||||
JOY_HAT_RIGHTUP = JOY_HAT_RIGHT | JOY_HAT_UP,
|
||||
JOY_HAT_RIGHTDOWN = JOY_HAT_RIGHT | JOY_HAT_DOWN,
|
||||
JOY_HAT_LEFTUP = JOY_HAT_LEFT | JOY_HAT_UP,
|
||||
JOY_HAT_LEFTDOWN = JOY_HAT_LEFT | JOY_HAT_DOWN
|
||||
};
|
||||
extern convar_t *joy_found;
|
||||
|
||||
qboolean Joy_IsActive( void );
|
||||
void Joy_HatMotionEvent( int id, byte hat, byte value );
|
||||
void Joy_AxisMotionEvent( int id, byte axis, short value );
|
||||
void Joy_BallMotionEvent( int id, byte ball, short xrel, short yrel );
|
||||
void Joy_ButtonEvent( int id, byte button, byte down );
|
||||
void Joy_AddEvent( int id );
|
||||
void Joy_RemoveEvent( int id );
|
||||
void Joy_FinalizeMove( float *fw, float *side, float *dpitch, float *dyaw );
|
||||
void Joy_Init( void );
|
||||
void Joy_Shutdown( void );
|
||||
void Joy_EnableTextInput(qboolean enable, qboolean force);
|
||||
|
||||
//
|
||||
// in_evdev.c
|
||||
//
|
||||
#ifdef XASH_USE_EVDEV
|
||||
void Evdev_SetGrab( qboolean grab );
|
||||
void Evdev_Shutdown( void );
|
||||
void Evdev_Init( void );
|
||||
#endif // XASH_USE_EVDEV
|
||||
|
||||
#endif//INPUT_H
|
||||
|
@ -18,12 +18,12 @@ GNU General Public License for more details.
|
||||
#include "client.h"
|
||||
#include "vgui_draw.h"
|
||||
|
||||
typedef struct key_s
|
||||
typedef struct
|
||||
{
|
||||
qboolean down;
|
||||
int repeats; // if > 1, it is autorepeating
|
||||
const char *binding;
|
||||
} key_t;
|
||||
} enginekey_t;
|
||||
|
||||
typedef struct keyname_s
|
||||
{
|
||||
@ -32,7 +32,7 @@ typedef struct keyname_s
|
||||
const char *binding; // default bind
|
||||
} keyname_t;
|
||||
|
||||
key_t keys[256];
|
||||
enginekey_t keys[256];
|
||||
|
||||
keyname_t keynames[] =
|
||||
{
|
||||
@ -548,15 +548,11 @@ void Key_Event( int key, qboolean down )
|
||||
// console key is hardcoded, so the user can never unbind it
|
||||
if( key == '`' || key == '~' )
|
||||
{
|
||||
// we are in typing mode. So don't switch to console
|
||||
if( (word)GetKeyboardLayout( 0 ) == (word)0x419 )
|
||||
{
|
||||
if( cls.key_dest != key_game )
|
||||
return;
|
||||
}
|
||||
// we are in typing mode, so don't switch to console
|
||||
if( cls.key_dest == key_message || !down )
|
||||
return;
|
||||
|
||||
if( !down ) return;
|
||||
Con_ToggleConsole_f();
|
||||
Con_ToggleConsole_f();
|
||||
return;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user