Engine input port. Incomplete integration of touch, gamepad, evdev input

This commit is contained in:
Alibek Omarov 2018-04-14 02:42:41 +03:00
parent 990d526a07
commit 4189af8b50
9 changed files with 3028 additions and 188 deletions

View File

@ -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

View File

@ -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 }
};

View File

@ -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
View 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
View 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

File diff suppressed because it is too large Load Diff

View File

@ -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( &current_pos );
ScreenToClient( host.hWnd, &current_pos );
#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 );
@ -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;

View File

@ -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

View File

@ -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;
}