mirror of
https://github.com/FWGS/xash3d-fwgs.git
synced 2026-08-05 11:35:05 +08:00
Compare commits
14 Commits
continuous
...
continuous
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
da4c4bb76a | ||
|
|
95b3271d68 | ||
|
|
3361a5d760 | ||
|
|
b725d2ece0 | ||
|
|
66bee8b468 | ||
|
|
5e664dc3e9 | ||
|
|
bfdfeb3dc0 | ||
|
|
49248f5e14 | ||
|
|
d03ea4c10a | ||
|
|
780dbd6183 | ||
|
|
50da79f1e0 | ||
|
|
62201900cf | ||
|
|
ae233ac491 | ||
|
|
dd1cb04cb7 |
@@ -1241,7 +1241,6 @@ void Key_EnumCmds_f( void );
|
|||||||
void Key_SetKeyDest( int key_dest );
|
void Key_SetKeyDest( int key_dest );
|
||||||
void Key_EnableTextInput( qboolean enable, qboolean force );
|
void Key_EnableTextInput( qboolean enable, qboolean force );
|
||||||
int Key_ToUpper( int key );
|
int Key_ToUpper( int key );
|
||||||
void OSK_Draw( void );
|
|
||||||
qboolean Cmd_GetKeysList( const char *s, char *completedname, int length, qboolean print_suggestions );
|
qboolean Cmd_GetKeysList( const char *s, char *completedname, int length, qboolean print_suggestions );
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -39,6 +39,10 @@ void IN_DeactivateMouse( void );
|
|||||||
void IN_MouseSavePos( void );
|
void IN_MouseSavePos( void );
|
||||||
void IN_MouseRestorePos( void );
|
void IN_MouseRestorePos( void );
|
||||||
void IN_ToggleClientMouse( int newstate, int oldstate );
|
void IN_ToggleClientMouse( int newstate, int oldstate );
|
||||||
|
void IN_GyroInit( void );
|
||||||
|
void IN_GyroCheckAvailability( void );
|
||||||
|
void IN_GyroEvent( vec3_t data );
|
||||||
|
void IN_GyroFinalizeMove( float *fw, float *side, float *dpitch, float *dyaw );
|
||||||
|
|
||||||
uint IN_CollectInputDevices( void );
|
uint IN_CollectInputDevices( void );
|
||||||
void IN_LockInputDevices( qboolean lock );
|
void IN_LockInputDevices( qboolean lock );
|
||||||
@@ -95,6 +99,15 @@ qboolean Touch_WantVisibleCursor( void );
|
|||||||
void Touch_NotifyResize( void );
|
void Touch_NotifyResize( void );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
//
|
||||||
|
// in_osk.c
|
||||||
|
//
|
||||||
|
extern convar_t osk_enable;
|
||||||
|
void OSK_Init( void );
|
||||||
|
qboolean OSK_KeyEvent( int key, int down );
|
||||||
|
void OSK_EnableTextInput( qboolean enable, qboolean force );
|
||||||
|
void OSK_Draw( void );
|
||||||
|
|
||||||
//
|
//
|
||||||
// in_joy.c
|
// in_joy.c
|
||||||
//
|
//
|
||||||
|
|||||||
120
engine/client/input/in_gyro.c
Normal file
120
engine/client/input/in_gyro.c
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
/*
|
||||||
|
in_gyro.c - System gyroscope input code
|
||||||
|
Copyright (C) 2026 Xash3D FWGS contributors
|
||||||
|
|
||||||
|
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"
|
||||||
|
|
||||||
|
static CVAR_DEFINE_AUTO( gyro_enable, "0", FCVAR_ARCHIVE | FCVAR_FILTERABLE, "enables aiming with built-in device gyroscope" );
|
||||||
|
static CVAR_DEFINE_AUTO( gyro_available, "0", FCVAR_READ_ONLY, "tells whether system gyroscope hardware is available or not" );
|
||||||
|
static CVAR_DEFINE_AUTO( gyro_pitch, "1.0", FCVAR_ARCHIVE | FCVAR_FILTERABLE, "built-in gyroscope sensitivity for looking up and down" );
|
||||||
|
static CVAR_DEFINE_AUTO( gyro_yaw, "1.0", FCVAR_ARCHIVE | FCVAR_FILTERABLE, "built-in gyroscope sensitivity for turning left and right" );
|
||||||
|
static CVAR_DEFINE_AUTO( gyro_roll, "0.0", FCVAR_ARCHIVE | FCVAR_FILTERABLE, "built-in gyroscope sensitivity when tilting the device sideways" );
|
||||||
|
static CVAR_DEFINE_AUTO( gyro_pitch_deadzone, "0.5", FCVAR_ARCHIVE | FCVAR_FILTERABLE, "built-in gyroscope pitch axis deadzone (deg/s)" );
|
||||||
|
static CVAR_DEFINE_AUTO( gyro_yaw_deadzone, "0.5", FCVAR_ARCHIVE | FCVAR_FILTERABLE, "built-in gyroscope yaw axis deadzone (deg/s)" );
|
||||||
|
static CVAR_DEFINE_AUTO( gyro_roll_deadzone, "0.5", FCVAR_ARCHIVE | FCVAR_FILTERABLE, "built-in gyroscope roll axis deadzone (deg/s)" );
|
||||||
|
|
||||||
|
// stores the latest instantaneous rotation rates from built-in gyroscope
|
||||||
|
static vec3_t gyro_speed;
|
||||||
|
|
||||||
|
/*
|
||||||
|
==============
|
||||||
|
IN_GyroInit
|
||||||
|
|
||||||
|
==============
|
||||||
|
*/
|
||||||
|
void IN_GyroInit( void )
|
||||||
|
{
|
||||||
|
Cvar_RegisterVariable( &gyro_enable );
|
||||||
|
Cvar_RegisterVariable( &gyro_available );
|
||||||
|
Cvar_RegisterVariable( &gyro_pitch );
|
||||||
|
Cvar_RegisterVariable( &gyro_yaw );
|
||||||
|
Cvar_RegisterVariable( &gyro_roll );
|
||||||
|
Cvar_RegisterVariable( &gyro_pitch_deadzone );
|
||||||
|
Cvar_RegisterVariable( &gyro_yaw_deadzone );
|
||||||
|
Cvar_RegisterVariable( &gyro_roll_deadzone );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
==============
|
||||||
|
IN_GyroCheckAvailability
|
||||||
|
|
||||||
|
One-time late check called after startup and configs
|
||||||
|
==============
|
||||||
|
*/
|
||||||
|
void IN_GyroCheckAvailability( void )
|
||||||
|
{
|
||||||
|
#if XASH_SDL
|
||||||
|
if( gyro_available.value )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if( SDLash_GyroIsAvailable() )
|
||||||
|
{
|
||||||
|
Cvar_FullSet( "gyro_available", "1", FCVAR_READ_ONLY );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=============
|
||||||
|
IN_GyroEvent
|
||||||
|
|
||||||
|
System gyroscope events from platform
|
||||||
|
=============
|
||||||
|
*/
|
||||||
|
void IN_GyroEvent( vec3_t data )
|
||||||
|
{
|
||||||
|
VectorCopy( data, gyro_speed );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=============
|
||||||
|
IN_GyroFinalizeMove
|
||||||
|
|
||||||
|
Apply gyro movement to view angles
|
||||||
|
=============
|
||||||
|
*/
|
||||||
|
void IN_GyroFinalizeMove( float *fw, float *side, float *dpitch, float *dyaw )
|
||||||
|
{
|
||||||
|
platform_orientation_t orient;
|
||||||
|
float orient_scale = 1.0f;
|
||||||
|
|
||||||
|
if( !gyro_enable.value || !gyro_available.value )
|
||||||
|
return;
|
||||||
|
|
||||||
|
orient = Platform_GetDisplayOrientation();
|
||||||
|
if( orient == ORIENTATION_LANDSCAPE_FLIPPED )
|
||||||
|
orient_scale = -1.0f;
|
||||||
|
|
||||||
|
// In Landscape mode axes are swapped relative to natural (Portrait) orientation
|
||||||
|
// Y axis rotation becomes Pitch (up/down)
|
||||||
|
// X axis rotation becomes Yaw (left/right)
|
||||||
|
float pitch_speed = -orient_scale * gyro_speed[1] * ( 180.0f / M_PI );
|
||||||
|
float yaw_speed = orient_scale * gyro_speed[0] * ( 180.0f / M_PI );
|
||||||
|
float roll_speed = orient_scale * gyro_speed[2] * ( 180.0f / M_PI );
|
||||||
|
|
||||||
|
if( fabs( pitch_speed ) < gyro_pitch_deadzone.value )
|
||||||
|
pitch_speed = 0.0f;
|
||||||
|
if( fabs( yaw_speed ) < gyro_yaw_deadzone.value )
|
||||||
|
yaw_speed = 0.0f;
|
||||||
|
if( fabs( roll_speed ) < gyro_roll_deadzone.value )
|
||||||
|
roll_speed = 0.0f;
|
||||||
|
|
||||||
|
*dpitch -= gyro_pitch.value * pitch_speed * host.realframetime;
|
||||||
|
*dyaw += gyro_yaw.value * yaw_speed * host.realframetime;
|
||||||
|
*dyaw += gyro_roll.value * roll_speed * host.realframetime;
|
||||||
|
|
||||||
|
VectorClear( gyro_speed );
|
||||||
|
}
|
||||||
@@ -197,7 +197,7 @@ static int Joy_GetHatValueForAxis( const engineAxis_t engineAxis )
|
|||||||
positive = JOY_HAT_RIGHT;
|
positive = JOY_HAT_RIGHT;
|
||||||
break;
|
break;
|
||||||
case JOY_AXIS_FWD:
|
case JOY_AXIS_FWD:
|
||||||
threshold = joy_side_key_threshold.value;
|
threshold = joy_forward_key_threshold.value;
|
||||||
negative = JOY_HAT_UP;
|
negative = JOY_HAT_UP;
|
||||||
positive = JOY_HAT_DOWN;
|
positive = JOY_HAT_DOWN;
|
||||||
break;
|
break;
|
||||||
@@ -318,7 +318,7 @@ void Joy_FinalizeMove( float *fw, float *side, float *dpitch, float *dyaw )
|
|||||||
const char *bind = joy_axis_binding.string;
|
const char *bind = joy_axis_binding.string;
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
for( i = 0; bind[i]; i++ )
|
for( i = 0; bind[i] && i < MAX_AXES; i++ )
|
||||||
{
|
{
|
||||||
switch( bind[i] )
|
switch( bind[i] )
|
||||||
{
|
{
|
||||||
@@ -158,9 +158,6 @@ static const keyname_t keynames[] =
|
|||||||
{ "INTERNATIONAL9", K_INTERNATIONAL + 8, "" },
|
{ "INTERNATIONAL9", K_INTERNATIONAL + 8, "" },
|
||||||
};
|
};
|
||||||
|
|
||||||
static void OSK_EnableTextInput( qboolean enable, qboolean force );
|
|
||||||
static qboolean OSK_KeyEvent( int key, int down );
|
|
||||||
static CVAR_DEFINE_AUTO( osk_enable, "0", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "enable built-in on-screen keyboard" );
|
|
||||||
static CVAR_DEFINE_AUTO( key_rotate, "0", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "rotate arrow keys (0-3)" );
|
static CVAR_DEFINE_AUTO( key_rotate, "0", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "rotate arrow keys (0-3)" );
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -200,7 +197,14 @@ static int Key_StringToKeynum( const char *str )
|
|||||||
|
|
||||||
// check for hex code
|
// check for hex code
|
||||||
if( str[0] == '0' && str[1] == 'x' )
|
if( str[0] == '0' && str[1] == 'x' )
|
||||||
return Q_atoi( str );
|
{
|
||||||
|
int key = Q_atoi( str );
|
||||||
|
|
||||||
|
if( key >= ARRAYSIZE( keys ))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
// scan for a text match
|
// scan for a text match
|
||||||
for( i = 0; i < ARRAYSIZE( keynames ); i++ )
|
for( i = 0; i < ARRAYSIZE( keynames ); i++ )
|
||||||
@@ -520,7 +524,7 @@ qboolean Cmd_GetKeysList( const char *s, char *completedname, int length, qboole
|
|||||||
const char *keyname = Key_KeynumToString( i );
|
const char *keyname = Key_KeynumToString( i );
|
||||||
|
|
||||||
if(( *s == '*' ) || !Q_strnicmp( keyname, s, len ))
|
if(( *s == '*' ) || !Q_strnicmp( keyname, s, len ))
|
||||||
Q_strncpy( keys_strings[numkeys++], keyname, sizeof( keys[0] ));
|
Q_strncpy( keys_strings[numkeys++], keyname, sizeof( keys_strings[0] ));
|
||||||
}
|
}
|
||||||
|
|
||||||
if( !numkeys ) return false;
|
if( !numkeys ) return false;
|
||||||
@@ -579,7 +583,6 @@ void Key_Init( void )
|
|||||||
for( i = 0; i < ARRAYSIZE( keynames ); i++ )
|
for( i = 0; i < ARRAYSIZE( keynames ); i++ )
|
||||||
Key_SetBinding( keynames[i].keynum, keynames[i].binding );
|
Key_SetBinding( keynames[i].keynum, keynames[i].binding );
|
||||||
|
|
||||||
Cvar_RegisterVariable( &osk_enable );
|
|
||||||
Cvar_RegisterVariable( &key_rotate );
|
Cvar_RegisterVariable( &key_rotate );
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -985,288 +988,3 @@ int Key_ToUpper( int keynum )
|
|||||||
|
|
||||||
return Q_toupper( keynum );
|
return Q_toupper( keynum );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* On-screen keyboard:
|
|
||||||
*
|
|
||||||
* 4 lines with 13 buttons each
|
|
||||||
* Left trigger == backspace
|
|
||||||
* Right trigger == space
|
|
||||||
* Any button press is button press on keyboard
|
|
||||||
*
|
|
||||||
* Our layout:
|
|
||||||
* 0 1 2 3 4 5 6 7 8 9 10 11 12
|
|
||||||
* +--+--+--+--+--+--+--+--+--+--+--+--+--+
|
|
||||||
* |` |1 |2 |3 |4 |5 |6 |7 |8 |9 |0 |- |= | 0
|
|
||||||
* +--+--+--+--+--+--+--+--+--+--+--+--+--+
|
|
||||||
* |q |w |e |r |t |y |u |i |o |p |[ |] |\ | 1
|
|
||||||
* +--+--+--+--+--+--+--+--+--+--+--+--+--+
|
|
||||||
* |CL|a |s |d |f |g |h |j |k |l |; |' |BS| 2
|
|
||||||
* +--+--+--+--+--+--+--+--+--+--+--+--+--+
|
|
||||||
* |SH|z |x |c |v |b |n |m |, |. |/ |SP|EN| 3
|
|
||||||
* +--+--+--+--+--+--+--+--+--+--+--+--+--+
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define MAX_OSK_ROWS 13
|
|
||||||
#define MAX_OSK_LINES 4
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
OSK_DEFAULT = 0,
|
|
||||||
OSK_UPPER, // on caps, shift
|
|
||||||
/*
|
|
||||||
OSK_RUSSIAN,
|
|
||||||
OSK_RUSSIAN_UPPER,
|
|
||||||
*/
|
|
||||||
OSK_LAST
|
|
||||||
};
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
OSK_TAB = 16,
|
|
||||||
OSK_SHIFT,
|
|
||||||
OSK_BACKSPACE,
|
|
||||||
OSK_ENTER,
|
|
||||||
OSK_SPECKEY_LAST
|
|
||||||
};
|
|
||||||
static const char *osk_keylayout[][4] =
|
|
||||||
{
|
|
||||||
{
|
|
||||||
"`1234567890-=", // 13
|
|
||||||
"qwertyuiop[]\\", // 13
|
|
||||||
"\x10" "asdfghjkl;'" "\x12", // 11 + caps on a left, enter on a right
|
|
||||||
"\x11" "zxcvbnm,./ " "\x13" // 10 + esc on left + shift on a left/right
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"~!@#$%^&*()_+",
|
|
||||||
"QWERTYUIOP{}|",
|
|
||||||
"\x10" "ASDFGHJKL:\"" "\x12",
|
|
||||||
"\x11" "ZXCVBNM<>? " "\x13"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct osk_s
|
|
||||||
{
|
|
||||||
qboolean enable;
|
|
||||||
int curlayout;
|
|
||||||
qboolean shift;
|
|
||||||
qboolean sending;
|
|
||||||
struct {
|
|
||||||
signed char x;
|
|
||||||
signed char y;
|
|
||||||
char val;
|
|
||||||
} curbutton;
|
|
||||||
} osk;
|
|
||||||
|
|
||||||
static qboolean OSK_KeyEvent( int key, int down )
|
|
||||||
{
|
|
||||||
if( !osk.enable || !osk_enable.value )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if( osk.sending )
|
|
||||||
{
|
|
||||||
osk.sending = false;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( osk.curbutton.val == 0 )
|
|
||||||
{
|
|
||||||
if( key == K_ENTER || key == K_A_BUTTON )
|
|
||||||
{
|
|
||||||
osk.curbutton.val = osk_keylayout[osk.curlayout][osk.curbutton.y][osk.curbutton.x];
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
switch ( key )
|
|
||||||
{
|
|
||||||
case K_A_BUTTON:
|
|
||||||
case K_ENTER:
|
|
||||||
switch( osk.curbutton.val )
|
|
||||||
{
|
|
||||||
case OSK_ENTER:
|
|
||||||
osk.sending = true;
|
|
||||||
Key_Event( K_ENTER, down );
|
|
||||||
//osk_enable = false; // TODO: handle multiline
|
|
||||||
break;
|
|
||||||
case OSK_SHIFT:
|
|
||||||
if( !down )
|
|
||||||
break;
|
|
||||||
|
|
||||||
if( osk.curlayout & 1 )
|
|
||||||
osk.curlayout--;
|
|
||||||
else
|
|
||||||
osk.curlayout++;
|
|
||||||
|
|
||||||
osk.shift = true;
|
|
||||||
osk.curbutton.val = osk_keylayout[osk.curlayout][osk.curbutton.y][osk.curbutton.x];
|
|
||||||
break;
|
|
||||||
case OSK_BACKSPACE:
|
|
||||||
Key_Event( K_BACKSPACE, down ); break;
|
|
||||||
case OSK_TAB:
|
|
||||||
Key_Event( K_TAB, down ); break;
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
int ch;
|
|
||||||
|
|
||||||
if( !down )
|
|
||||||
{
|
|
||||||
if( osk.shift && osk.curlayout & 1 )
|
|
||||||
osk.curlayout--;
|
|
||||||
|
|
||||||
osk.shift = false;
|
|
||||||
osk.curbutton.val = osk_keylayout[osk.curlayout][osk.curbutton.y][osk.curbutton.x];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
ch = (byte)osk.curbutton.val;
|
|
||||||
|
|
||||||
// do not pass UTF-8 sequence into the engine, convert it here
|
|
||||||
if( !cls.accept_utf8 )
|
|
||||||
ch = Con_UtfProcessCharForce( ch );
|
|
||||||
|
|
||||||
if( !ch )
|
|
||||||
break;
|
|
||||||
|
|
||||||
CL_CharEvent( ch );
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case K_UPARROW:
|
|
||||||
if( down && --osk.curbutton.y < 0 )
|
|
||||||
{
|
|
||||||
osk.curbutton.y = MAX_OSK_LINES - 1;
|
|
||||||
osk.curbutton.val = 0;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case K_DOWNARROW:
|
|
||||||
if( down && ++osk.curbutton.y >= MAX_OSK_LINES )
|
|
||||||
{
|
|
||||||
osk.curbutton.y = 0;
|
|
||||||
osk.curbutton.val = 0;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case K_LEFTARROW:
|
|
||||||
if( down && --osk.curbutton.x < 0 )
|
|
||||||
osk.curbutton.x = MAX_OSK_ROWS - 1;
|
|
||||||
break;
|
|
||||||
case K_RIGHTARROW:
|
|
||||||
if( down && ++osk.curbutton.x >= MAX_OSK_ROWS )
|
|
||||||
osk.curbutton.x = 0;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
osk.curbutton.val = osk_keylayout[osk.curlayout][osk.curbutton.y][osk.curbutton.x];
|
|
||||||
return true;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
=============
|
|
||||||
OSK_EnableTextInput
|
|
||||||
|
|
||||||
Enables built-in IME
|
|
||||||
=============
|
|
||||||
*/
|
|
||||||
static void OSK_EnableTextInput( qboolean enable, qboolean force )
|
|
||||||
{
|
|
||||||
qboolean old = osk.enable;
|
|
||||||
|
|
||||||
osk.enable = enable;
|
|
||||||
|
|
||||||
if( osk.enable && (!old || force) )
|
|
||||||
{
|
|
||||||
osk.curlayout = 0;
|
|
||||||
osk.curbutton.val = osk_keylayout[osk.curlayout][osk.curbutton.y][osk.curbutton.x];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#define X_START 0.1347475f
|
|
||||||
#define Y_START 0.567f
|
|
||||||
#define X_STEP 0.05625
|
|
||||||
#define Y_STEP 0.0825
|
|
||||||
|
|
||||||
/*
|
|
||||||
============
|
|
||||||
Joy_DrawSymbolButton
|
|
||||||
|
|
||||||
Draw button with symbol on it
|
|
||||||
============
|
|
||||||
*/
|
|
||||||
static void OSK_DrawSymbolButton( int symb, float x, float y, float width, float height )
|
|
||||||
{
|
|
||||||
cl_font_t *font = Con_GetCurFont();
|
|
||||||
byte color[] = { 255, 255, 255, 255 };
|
|
||||||
int x1 = x * refState.width,
|
|
||||||
y1 = y * refState.height,
|
|
||||||
w = width * refState.width,
|
|
||||||
h = height * refState.height;
|
|
||||||
|
|
||||||
if( symb == osk.curbutton.val )
|
|
||||||
ref.dllFuncs.FillRGBA( kRenderTransTexture, x1, y1, w, h, 255, 160, 0, 100 );
|
|
||||||
|
|
||||||
if( !symb || symb == ' ' || (symb >= OSK_TAB && symb < OSK_SPECKEY_LAST ) )
|
|
||||||
return;
|
|
||||||
|
|
||||||
CL_DrawCharacter(
|
|
||||||
x1 + width * 0.4 * refState.width,
|
|
||||||
y1 + height * 0.4 * refState.height,
|
|
||||||
symb, color, font, 0 );
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
=============
|
|
||||||
Joy_DrawSpecialButton
|
|
||||||
|
|
||||||
Draw special button, like shift, enter or esc
|
|
||||||
=============
|
|
||||||
*/
|
|
||||||
static void OSK_DrawSpecialButton( const char *name, float x, float y, float width, float height )
|
|
||||||
{
|
|
||||||
byte color[] = { 0, 255, 0, 255 };
|
|
||||||
|
|
||||||
Con_DrawString(
|
|
||||||
x * refState.width + width * 0.4 * refState.width,
|
|
||||||
y * refState.height + height * 0.4 * refState.height,
|
|
||||||
name,
|
|
||||||
color );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
=============
|
|
||||||
Joy_DrawOnScreenKeyboard
|
|
||||||
|
|
||||||
Draw on screen keyboard, if enabled
|
|
||||||
=============
|
|
||||||
*/
|
|
||||||
void OSK_Draw( void )
|
|
||||||
{
|
|
||||||
const char **curlayout = osk_keylayout[osk.curlayout]; // shortcut :)
|
|
||||||
float x, y;
|
|
||||||
int i, j;
|
|
||||||
|
|
||||||
if( !osk.enable || !osk_enable.value || !osk.curbutton.val )
|
|
||||||
return;
|
|
||||||
|
|
||||||
// draw keyboard
|
|
||||||
ref.dllFuncs.FillRGBA( kRenderTransTexture, X_START * refState.width, Y_START * refState.height,
|
|
||||||
X_STEP * MAX_OSK_ROWS * refState.width,
|
|
||||||
Y_STEP * MAX_OSK_LINES * refState.height, 100, 100, 100, 100 );
|
|
||||||
|
|
||||||
OSK_DrawSpecialButton( "-]", X_START, Y_START + Y_STEP * 2, X_STEP, Y_STEP );
|
|
||||||
OSK_DrawSpecialButton( "<-", X_START + X_STEP * 12, Y_START + Y_STEP * 2, X_STEP, Y_STEP );
|
|
||||||
|
|
||||||
OSK_DrawSpecialButton( "sh", X_START, Y_START + Y_STEP * 3, X_STEP, Y_STEP );
|
|
||||||
OSK_DrawSpecialButton( "en", X_START + X_STEP * 12, Y_START + Y_STEP * 3, X_STEP, Y_STEP );
|
|
||||||
|
|
||||||
for( y = Y_START, j = 0; j < MAX_OSK_LINES; j++, y += Y_STEP )
|
|
||||||
for( x = X_START, i = 0; i < MAX_OSK_ROWS; i++, x += X_STEP )
|
|
||||||
OSK_DrawSymbolButton( curlayout[j][i], x, y, X_STEP, Y_STEP );
|
|
||||||
}
|
|
||||||
312
engine/client/input/in_osk.c
Normal file
312
engine/client/input/in_osk.c
Normal file
@@ -0,0 +1,312 @@
|
|||||||
|
/*
|
||||||
|
in_osk.c - on-screen keyboard input
|
||||||
|
Copyright (C) 2016-2026 Alibek Omarov
|
||||||
|
|
||||||
|
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"
|
||||||
|
|
||||||
|
CVAR_DEFINE_AUTO( osk_enable, "0", FCVAR_ARCHIVE | FCVAR_FILTERABLE, "enable built-in on-screen keyboard" );
|
||||||
|
|
||||||
|
/* On-screen keyboard:
|
||||||
|
*
|
||||||
|
* 4 lines with 13 buttons each
|
||||||
|
* Left trigger == backspace
|
||||||
|
* Right trigger == space
|
||||||
|
* Any button press is button press on keyboard
|
||||||
|
*
|
||||||
|
* Our layout:
|
||||||
|
* 0 1 2 3 4 5 6 7 8 9 10 11 12
|
||||||
|
* +--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||||
|
* |` |1 |2 |3 |4 |5 |6 |7 |8 |9 |0 |- |= | 0
|
||||||
|
* +--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||||
|
* |q |w |e |r |t |y |u |i |o |p |[ |] |\ | 1
|
||||||
|
* +--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||||
|
* |CL|a |s |d |f |g |h |j |k |l |; |' |BS| 2
|
||||||
|
* +--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||||
|
* |SH|z |x |c |v |b |n |m |, |. |/ |SP|EN| 3
|
||||||
|
* +--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define MAX_OSK_ROWS 13
|
||||||
|
#define MAX_OSK_LINES 4
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
OSK_DEFAULT = 0,
|
||||||
|
OSK_UPPER, // on caps, shift
|
||||||
|
/*
|
||||||
|
OSK_RUSSIAN,
|
||||||
|
OSK_RUSSIAN_UPPER,
|
||||||
|
*/
|
||||||
|
OSK_LAST
|
||||||
|
};
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
OSK_TAB = 16,
|
||||||
|
OSK_SHIFT,
|
||||||
|
OSK_BACKSPACE,
|
||||||
|
OSK_ENTER,
|
||||||
|
OSK_SPECKEY_LAST
|
||||||
|
};
|
||||||
|
static const char *osk_keylayout[][4] =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
"`1234567890-=", // 13
|
||||||
|
"qwertyuiop[]\\", // 13
|
||||||
|
"\x10" "asdfghjkl;'" "\x12", // 11 + caps on a left, enter on a right
|
||||||
|
"\x11" "zxcvbnm,./ " "\x13" // 10 + esc on left + shift on a left/right
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"~!@#$%^&*()_+",
|
||||||
|
"QWERTYUIOP{}|",
|
||||||
|
"\x10" "ASDFGHJKL:\"" "\x12",
|
||||||
|
"\x11" "ZXCVBNM<>? " "\x13"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct osk_s
|
||||||
|
{
|
||||||
|
qboolean enable;
|
||||||
|
int curlayout;
|
||||||
|
qboolean shift;
|
||||||
|
qboolean sending;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
signed char x;
|
||||||
|
signed char y;
|
||||||
|
char val;
|
||||||
|
} curbutton;
|
||||||
|
} osk;
|
||||||
|
|
||||||
|
qboolean OSK_KeyEvent( int key, int down )
|
||||||
|
{
|
||||||
|
if( !osk.enable || !osk_enable.value )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if( osk.sending )
|
||||||
|
{
|
||||||
|
osk.sending = false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( osk.curbutton.val == 0 )
|
||||||
|
{
|
||||||
|
if( key == K_ENTER || key == K_A_BUTTON )
|
||||||
|
{
|
||||||
|
osk.curbutton.val = osk_keylayout[osk.curlayout][osk.curbutton.y][osk.curbutton.x];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
switch( key )
|
||||||
|
{
|
||||||
|
case K_A_BUTTON:
|
||||||
|
case K_ENTER:
|
||||||
|
switch( osk.curbutton.val )
|
||||||
|
{
|
||||||
|
case OSK_ENTER:
|
||||||
|
osk.sending = true;
|
||||||
|
Key_Event( K_ENTER, down );
|
||||||
|
// osk_enable = false; // TODO: handle multiline
|
||||||
|
break;
|
||||||
|
case OSK_SHIFT:
|
||||||
|
if( !down )
|
||||||
|
break;
|
||||||
|
|
||||||
|
if( osk.curlayout & 1 )
|
||||||
|
osk.curlayout--;
|
||||||
|
else
|
||||||
|
osk.curlayout++;
|
||||||
|
|
||||||
|
osk.shift = true;
|
||||||
|
osk.curbutton.val = osk_keylayout[osk.curlayout][osk.curbutton.y][osk.curbutton.x];
|
||||||
|
break;
|
||||||
|
case OSK_BACKSPACE:
|
||||||
|
Key_Event( K_BACKSPACE, down );
|
||||||
|
break;
|
||||||
|
case OSK_TAB:
|
||||||
|
Key_Event( K_TAB, down );
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
int ch;
|
||||||
|
|
||||||
|
if( !down )
|
||||||
|
{
|
||||||
|
if( osk.shift && osk.curlayout & 1 )
|
||||||
|
osk.curlayout--;
|
||||||
|
|
||||||
|
osk.shift = false;
|
||||||
|
osk.curbutton.val = osk_keylayout[osk.curlayout][osk.curbutton.y][osk.curbutton.x];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ch = (byte)osk.curbutton.val;
|
||||||
|
|
||||||
|
// do not pass UTF-8 sequence into the engine, convert it here
|
||||||
|
if( !cls.accept_utf8 )
|
||||||
|
ch = Con_UtfProcessCharForce( ch );
|
||||||
|
|
||||||
|
if( !ch )
|
||||||
|
break;
|
||||||
|
|
||||||
|
CL_CharEvent( ch );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case K_UPARROW:
|
||||||
|
if( down && --osk.curbutton.y < 0 )
|
||||||
|
{
|
||||||
|
osk.curbutton.y = MAX_OSK_LINES - 1;
|
||||||
|
osk.curbutton.val = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case K_DOWNARROW:
|
||||||
|
if( down && ++osk.curbutton.y >= MAX_OSK_LINES )
|
||||||
|
{
|
||||||
|
osk.curbutton.y = 0;
|
||||||
|
osk.curbutton.val = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case K_LEFTARROW:
|
||||||
|
if( down && --osk.curbutton.x < 0 )
|
||||||
|
osk.curbutton.x = MAX_OSK_ROWS - 1;
|
||||||
|
break;
|
||||||
|
case K_RIGHTARROW:
|
||||||
|
if( down && ++osk.curbutton.x >= MAX_OSK_ROWS )
|
||||||
|
osk.curbutton.x = 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
osk.curbutton.val = osk_keylayout[osk.curlayout][osk.curbutton.y][osk.curbutton.x];
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=============
|
||||||
|
OSK_EnableTextInput
|
||||||
|
|
||||||
|
Enables built-in IME
|
||||||
|
=============
|
||||||
|
*/
|
||||||
|
void OSK_EnableTextInput( qboolean enable, qboolean force )
|
||||||
|
{
|
||||||
|
qboolean old = osk.enable;
|
||||||
|
|
||||||
|
osk.enable = enable;
|
||||||
|
|
||||||
|
if( osk.enable && ( !old || force ))
|
||||||
|
{
|
||||||
|
osk.curlayout = 0;
|
||||||
|
osk.curbutton.val = osk_keylayout[osk.curlayout][osk.curbutton.y][osk.curbutton.x];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define X_START 0.1347475f
|
||||||
|
#define Y_START 0.567f
|
||||||
|
#define X_STEP 0.05625
|
||||||
|
#define Y_STEP 0.0825
|
||||||
|
|
||||||
|
/*
|
||||||
|
============
|
||||||
|
OSK_DrawSymbolButton
|
||||||
|
|
||||||
|
Draw button with symbol on it
|
||||||
|
============
|
||||||
|
*/
|
||||||
|
static void OSK_DrawSymbolButton( int symb, float x, float y, float width, float height )
|
||||||
|
{
|
||||||
|
cl_font_t *font = Con_GetCurFont();
|
||||||
|
byte color[] = { 255, 255, 255, 255 };
|
||||||
|
int x1 = x * refState.width,
|
||||||
|
y1 = y * refState.height,
|
||||||
|
w = width * refState.width,
|
||||||
|
h = height * refState.height;
|
||||||
|
|
||||||
|
if( symb == osk.curbutton.val )
|
||||||
|
ref.dllFuncs.FillRGBA( kRenderTransTexture, x1, y1, w, h, 255, 160, 0, 100 );
|
||||||
|
|
||||||
|
if( !symb || symb == ' ' || ( symb >= OSK_TAB && symb < OSK_SPECKEY_LAST ))
|
||||||
|
return;
|
||||||
|
|
||||||
|
CL_DrawCharacter(
|
||||||
|
x1 + width * 0.4 * refState.width,
|
||||||
|
y1 + height * 0.4 * refState.height,
|
||||||
|
symb, color, font, 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=============
|
||||||
|
OSK_DrawSpecialButton
|
||||||
|
|
||||||
|
Draw special button, like shift, enter or esc
|
||||||
|
=============
|
||||||
|
*/
|
||||||
|
static void OSK_DrawSpecialButton( const char *name, float x, float y, float width, float height )
|
||||||
|
{
|
||||||
|
byte color[] = { 0, 255, 0, 255 };
|
||||||
|
|
||||||
|
Con_DrawString(
|
||||||
|
x * refState.width + width * 0.4 * refState.width,
|
||||||
|
y * refState.height + height * 0.4 * refState.height,
|
||||||
|
name,
|
||||||
|
color );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=============
|
||||||
|
OSK_Draw
|
||||||
|
|
||||||
|
Draw on screen keyboard, if enabled
|
||||||
|
=============
|
||||||
|
*/
|
||||||
|
void OSK_Draw( void )
|
||||||
|
{
|
||||||
|
const char **curlayout = osk_keylayout[osk.curlayout]; // shortcut :)
|
||||||
|
float x, y;
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
if( !osk.enable || !osk_enable.value || !osk.curbutton.val )
|
||||||
|
return;
|
||||||
|
|
||||||
|
// draw keyboard
|
||||||
|
ref.dllFuncs.FillRGBA( kRenderTransTexture, X_START * refState.width, Y_START * refState.height,
|
||||||
|
X_STEP * MAX_OSK_ROWS * refState.width,
|
||||||
|
Y_STEP * MAX_OSK_LINES * refState.height, 100, 100, 100, 100 );
|
||||||
|
|
||||||
|
OSK_DrawSpecialButton( "-]", X_START, Y_START + Y_STEP * 2, X_STEP, Y_STEP );
|
||||||
|
OSK_DrawSpecialButton( "<-", X_START + X_STEP * 12, Y_START + Y_STEP * 2, X_STEP, Y_STEP );
|
||||||
|
|
||||||
|
OSK_DrawSpecialButton( "sh", X_START, Y_START + Y_STEP * 3, X_STEP, Y_STEP );
|
||||||
|
OSK_DrawSpecialButton( "en", X_START + X_STEP * 12, Y_START + Y_STEP * 3, X_STEP, Y_STEP );
|
||||||
|
|
||||||
|
for( y = Y_START, j = 0; j < MAX_OSK_LINES; j++, y += Y_STEP )
|
||||||
|
for( x = X_START, i = 0; i < MAX_OSK_ROWS; i++, x += X_STEP )
|
||||||
|
OSK_DrawSymbolButton( curlayout[j][i], x, y, X_STEP, Y_STEP );
|
||||||
|
}
|
||||||
|
|
||||||
|
void OSK_Init( void )
|
||||||
|
{
|
||||||
|
Cvar_RegisterVariable( &osk_enable );
|
||||||
|
}
|
||||||
@@ -185,10 +185,10 @@ void Touch_NotifyResize( void )
|
|||||||
|
|
||||||
static inline float Touch_AspectRatio( void )
|
static inline float Touch_AspectRatio( void )
|
||||||
{
|
{
|
||||||
if( touch.config_aspect_ratio )
|
if( touch.config_aspect_ratio >= 0.25f )
|
||||||
return touch.config_aspect_ratio;
|
return touch.config_aspect_ratio;
|
||||||
|
|
||||||
if( touch.actual_aspect_ratio )
|
if( touch.actual_aspect_ratio >= 0.25f )
|
||||||
return touch.actual_aspect_ratio;
|
return touch.actual_aspect_ratio;
|
||||||
|
|
||||||
if( refState.width && refState.height )
|
if( refState.width && refState.height )
|
||||||
@@ -369,7 +369,7 @@ static void Touch_ExportConfig_f( void )
|
|||||||
string profilebase;
|
string profilebase;
|
||||||
|
|
||||||
COM_FileBase( name, profilebase, sizeof( profilebase ));
|
COM_FileBase( name, profilebase, sizeof( profilebase ));
|
||||||
Q_snprintf( profilename, sizeof( profilebase ), "touch_profiles/%s (copy).cfg", profilebase );
|
Q_snprintf( profilename, sizeof( profilename ), "touch_profiles/%s (copy).cfg", profilebase );
|
||||||
}
|
}
|
||||||
else Q_strncpy( profilename, name, sizeof( profilename ));
|
else Q_strncpy( profilename, name, sizeof( profilename ));
|
||||||
|
|
||||||
@@ -588,7 +588,7 @@ static void Touch_RemoveButtonFromList( touchbuttonlist_t *list, const char *nam
|
|||||||
|
|
||||||
IN_TouchEditClear();
|
IN_TouchEditClear();
|
||||||
|
|
||||||
while(( button = Touch_FindFirst( &touch.list_user, name, privileged )))
|
while(( button = Touch_FindFirst( list, name, privileged )))
|
||||||
{
|
{
|
||||||
if( button->prev )
|
if( button->prev )
|
||||||
button->prev->next = button->next;
|
button->prev->next = button->next;
|
||||||
@@ -860,8 +860,7 @@ void Touch_AddClientButton( const char *name, const char *texture, const char *c
|
|||||||
if( !touch.initialized )
|
if( !touch.initialized )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if( round )
|
IN_TouchCheckCoords( &x1, &y1, &x2, &y2 );
|
||||||
IN_TouchCheckCoords( &x1, &y1, &x2, &y2 );
|
|
||||||
|
|
||||||
if( round == round_aspect )
|
if( round == round_aspect )
|
||||||
y2 = y1 + ( x2 - x1 ) / (Touch_AspectRatio()) * aspect;
|
y2 = y1 + ( x2 - x1 ) / (Touch_AspectRatio()) * aspect;
|
||||||
@@ -1068,7 +1067,7 @@ static void Touch_InitEditor( void )
|
|||||||
temp = Touch_AddButton( &touch.list_edit, "close", "touch_default/edit_close", "touch_disableedit", 0, y, x, y + 0.1f, color, true );
|
temp = Touch_AddButton( &touch.list_edit, "close", "touch_default/edit_close", "touch_disableedit", 0, y, x, y + 0.1f, color, true );
|
||||||
SetBits( temp->flags, TOUCH_FL_NOEDIT );
|
SetBits( temp->flags, TOUCH_FL_NOEDIT );
|
||||||
|
|
||||||
temp = Touch_AddButton( &touch.list_edit, "close", "#Close and save", "", x, y, x + 0.2f, y + 0.1f, color, true );
|
temp = Touch_AddButton( &touch.list_edit, "close_label", "#Close and save", "", x, y, x + 0.2f, y + 0.1f, color, true );
|
||||||
SetBits( temp->flags, TOUCH_FL_NOEDIT );
|
SetBits( temp->flags, TOUCH_FL_NOEDIT );
|
||||||
|
|
||||||
y += 0.2f;
|
y += 0.2f;
|
||||||
@@ -1076,7 +1075,7 @@ static void Touch_InitEditor( void )
|
|||||||
temp = Touch_AddButton( &touch.list_edit, "cancel", "touch_default/edit_reset", "touch_reloadconfig", 0, y, x, y + 0.1f, color, true );
|
temp = Touch_AddButton( &touch.list_edit, "cancel", "touch_default/edit_reset", "touch_reloadconfig", 0, y, x, y + 0.1f, color, true );
|
||||||
SetBits( temp->flags, TOUCH_FL_NOEDIT );
|
SetBits( temp->flags, TOUCH_FL_NOEDIT );
|
||||||
|
|
||||||
temp = Touch_AddButton( &touch.list_edit, "close", "#Cancel and reset", "", x, y, x + 0.2f, y + 0.1f, color, true );
|
temp = Touch_AddButton( &touch.list_edit, "cancel_label", "#Cancel and reset", "", x, y, x + 0.2f, y + 0.1f, color, true );
|
||||||
SetBits( temp->flags, TOUCH_FL_NOEDIT );
|
SetBits( temp->flags, TOUCH_FL_NOEDIT );
|
||||||
|
|
||||||
y += 0.2f;
|
y += 0.2f;
|
||||||
@@ -1256,12 +1255,21 @@ static void Touch_DrawTexture( float x1, float y1, float x2, float y2, int textu
|
|||||||
0, 0, 1, 1, texture );
|
0, 0, 1, 1, texture );
|
||||||
}
|
}
|
||||||
|
|
||||||
#define GRID_COUNT_X ((int)touch_grid_count.value )
|
static inline int Touch_GridCountX( void )
|
||||||
#define GRID_COUNT_Y (((int)touch_grid_count.value ) * Touch_AspectRatio( ))
|
{
|
||||||
#define GRID_X ( 1.0f / GRID_COUNT_X )
|
return Q_max((int)touch_grid_count.value, 1 );
|
||||||
#define GRID_Y ( 1.0f / Touch_AspectRatio() / GRID_COUNT_X )
|
}
|
||||||
#define GRID_ROUND_X( x ) ((float)round(( x ) * GRID_COUNT_X ) / GRID_COUNT_X )
|
|
||||||
#define GRID_ROUND_Y( x ) ((float)round(( x ) * GRID_COUNT_Y ) / GRID_COUNT_Y )
|
static inline int Touch_GridCountY( void )
|
||||||
|
{
|
||||||
|
float grid_count_y = touch_grid_count.value * Touch_AspectRatio();
|
||||||
|
return Q_max((int)grid_count_y, 1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
#define GRID_X ( 1.0f / Touch_GridCountX( ))
|
||||||
|
#define GRID_Y ( 1.0f / Touch_GridCountY( ))
|
||||||
|
#define GRID_ROUND_X( x ) ((float)round(( x ) * Touch_GridCountX() ) / Touch_GridCountX())
|
||||||
|
#define GRID_ROUND_Y( x ) ((float)round(( x ) * Touch_GridCountY() ) / Touch_GridCountY())
|
||||||
|
|
||||||
static void IN_TouchCheckCoords( float *x1, float *y1, float *x2, float *y2 )
|
static void IN_TouchCheckCoords( float *x1, float *y1, float *x2, float *y2 )
|
||||||
{
|
{
|
||||||
@@ -445,6 +445,10 @@ void IN_Init( void )
|
|||||||
{
|
{
|
||||||
IN_StartupMouse( );
|
IN_StartupMouse( );
|
||||||
|
|
||||||
|
IN_GyroInit();
|
||||||
|
|
||||||
|
OSK_Init();
|
||||||
|
|
||||||
Joy_Init(); // common joystick support init
|
Joy_Init(); // common joystick support init
|
||||||
|
|
||||||
Touch_Init();
|
Touch_Init();
|
||||||
@@ -560,6 +564,7 @@ static void IN_CollectInput( float *forward, float *side, float *pitch, float *y
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IN_GyroFinalizeMove( forward, side, pitch, yaw );
|
||||||
Joy_FinalizeMove( forward, side, pitch, yaw );
|
Joy_FinalizeMove( forward, side, pitch, yaw );
|
||||||
Touch_GetMove( forward, side, pitch, yaw );
|
Touch_GetMove( forward, side, pitch, yaw );
|
||||||
|
|
||||||
@@ -514,17 +514,26 @@ static void CL_ParseSoundPacketGS( sizebuf_t *msg )
|
|||||||
static void CL_ParseSpawnStaticSound( sizebuf_t *msg )
|
static void CL_ParseSpawnStaticSound( sizebuf_t *msg )
|
||||||
{
|
{
|
||||||
vec3_t pos;
|
vec3_t pos;
|
||||||
int handle, entnum, pitch, flags;
|
int sound, entnum, pitch, flags;
|
||||||
float volume, attn;
|
float volume, attn;
|
||||||
|
sound_t handle = 0;
|
||||||
|
|
||||||
MSG_ReadVec3Coord( msg, pos );
|
MSG_ReadVec3Coord( msg, pos );
|
||||||
handle = MSG_ReadShort( msg );
|
sound = MSG_ReadShort( msg );
|
||||||
volume = MSG_ReadByte( msg ) * ( 1.0f / 255.0f );
|
volume = MSG_ReadByte( msg ) * ( 1.0f / 255.0f );
|
||||||
attn = MSG_ReadByte( msg ) * ( 1.0f / 64.0f );
|
attn = MSG_ReadByte( msg ) * ( 1.0f / 64.0f );
|
||||||
entnum = MSG_ReadShort( msg );
|
entnum = MSG_ReadShort( msg );
|
||||||
pitch = MSG_ReadByte( msg );
|
pitch = MSG_ReadByte( msg );
|
||||||
flags = MSG_ReadByte( msg );
|
flags = MSG_ReadByte( msg );
|
||||||
|
|
||||||
|
if( FBitSet( flags, SND_SENTENCE ))
|
||||||
|
{
|
||||||
|
char sentenceName[32];
|
||||||
|
Q_snprintf( sentenceName, sizeof( sentenceName ), "!%i", sound );
|
||||||
|
handle = S_RegisterSound( sentenceName );
|
||||||
|
}
|
||||||
|
else handle = cl.sound_index[sound]; // see precached sound
|
||||||
|
|
||||||
S_AmbientSound( pos, entnum, handle, volume, attn, pitch, flags );
|
S_AmbientSound( pos, entnum, handle, volume, attn, pitch, flags );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1276,6 +1276,10 @@ int EXPORT Host_Main( int argc, char **argv, const char *progname, int bChangeGa
|
|||||||
Cbuf_ExecStuffCmds(); // execute stuffcmds (commandline)
|
Cbuf_ExecStuffCmds(); // execute stuffcmds (commandline)
|
||||||
SCR_CheckStartupVids(); // must be last
|
SCR_CheckStartupVids(); // must be last
|
||||||
|
|
||||||
|
#ifndef XASH_DEDICATED
|
||||||
|
IN_GyroCheckAvailability();
|
||||||
|
#endif
|
||||||
|
|
||||||
if( Sys_GetParmFromCmdLine( "-timedemo", demoname ))
|
if( Sys_GetParmFromCmdLine( "-timedemo", demoname ))
|
||||||
Cbuf_AddTextf( "timedemo %s\n", demoname );
|
Cbuf_AddTextf( "timedemo %s\n", demoname );
|
||||||
|
|
||||||
|
|||||||
@@ -40,6 +40,17 @@ void Platform_MessageBox( const char *title, const char *message, qboolean paren
|
|||||||
void Platform_SetStatus( const char *status );
|
void Platform_SetStatus( const char *status );
|
||||||
qboolean Platform_DebuggerPresent( void );
|
qboolean Platform_DebuggerPresent( void );
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
ORIENTATION_UNKNOWN = 0,
|
||||||
|
ORIENTATION_LANDSCAPE,
|
||||||
|
ORIENTATION_LANDSCAPE_FLIPPED,
|
||||||
|
ORIENTATION_PORTRAIT,
|
||||||
|
ORIENTATION_PORTRAIT_FLIPPED
|
||||||
|
} platform_orientation_t;
|
||||||
|
|
||||||
|
platform_orientation_t Platform_GetDisplayOrientation( void );
|
||||||
|
|
||||||
// legacy iOS port functions
|
// legacy iOS port functions
|
||||||
#if XASH_IOS
|
#if XASH_IOS
|
||||||
int IOS_GetArgs( char ***argv );
|
int IOS_GetArgs( char ***argv );
|
||||||
@@ -64,6 +75,7 @@ char *Posix_Input( void );
|
|||||||
void SDLash_Init( void );
|
void SDLash_Init( void );
|
||||||
void SDLash_Shutdown( void );
|
void SDLash_Shutdown( void );
|
||||||
void SDLash_NanoSleep( int nsec );
|
void SDLash_NanoSleep( int nsec );
|
||||||
|
qboolean SDLash_GyroIsAvailable( void );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if XASH_ANDROID
|
#if XASH_ANDROID
|
||||||
|
|||||||
@@ -368,6 +368,11 @@ static void SDLash_EventHandler( SDL_Event *event )
|
|||||||
#endif
|
#endif
|
||||||
SDLash_HandleGameControllerEvent( event );
|
SDLash_HandleGameControllerEvent( event );
|
||||||
break;
|
break;
|
||||||
|
#if SDL_VERSION_ATLEAST( 2, 0, 14 )
|
||||||
|
case SDL_SENSORUPDATE:
|
||||||
|
SDLash_SensorUpdate( event->sensor );
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
|
||||||
case SDL_WINDOWEVENT:
|
case SDL_WINDOWEVENT:
|
||||||
if( event->window.windowID != SDL_GetWindowID( host.hWnd ) )
|
if( event->window.windowID != SDL_GetWindowID( host.hWnd ) )
|
||||||
|
|||||||
@@ -35,5 +35,15 @@ void SDLash_FreeCursors( void );
|
|||||||
//
|
//
|
||||||
void SDLash_HandleGameControllerEvent( SDL_Event *ev );
|
void SDLash_HandleGameControllerEvent( SDL_Event *ev );
|
||||||
|
|
||||||
|
//
|
||||||
|
// sensor_sdl2.c
|
||||||
|
//
|
||||||
|
void SDLash_InitSensors( void );
|
||||||
|
void SDLash_ShutdownSensors( void );
|
||||||
|
qboolean SDLash_GyroIsAvailable( void );
|
||||||
|
#if SDL_VERSION_ATLEAST( 2, 0, 14 )
|
||||||
|
void SDLash_SensorUpdate( SDL_SensorEvent sensor );
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif // XASH_SDL
|
#endif // XASH_SDL
|
||||||
#endif // KEYWRAPPER_H
|
#endif // KEYWRAPPER_H
|
||||||
|
|||||||
103
engine/platform/sdl2/sensor_sdl2.c
Normal file
103
engine/platform/sdl2/sensor_sdl2.c
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
/*
|
||||||
|
sensor_sdl2.c - SDL2 sensor handling
|
||||||
|
Copyright (C) 2026 Xash3D FWGS contributors
|
||||||
|
|
||||||
|
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 <SDL.h>
|
||||||
|
#include "common.h"
|
||||||
|
#include "input.h"
|
||||||
|
#include "platform_sdl2.h"
|
||||||
|
|
||||||
|
#if SDL_VERSION_ATLEAST( 2, 0, 14 )
|
||||||
|
static SDL_SensorID g_system_gyro_id = -1;
|
||||||
|
static SDL_Sensor *g_system_gyro;
|
||||||
|
|
||||||
|
/*
|
||||||
|
==============
|
||||||
|
SDLash_InitSensors
|
||||||
|
|
||||||
|
==============
|
||||||
|
*/
|
||||||
|
void SDLash_InitSensors( void )
|
||||||
|
{
|
||||||
|
if( SDL_InitSubSystem( SDL_INIT_SENSOR ) == 0 )
|
||||||
|
{
|
||||||
|
int num_sensors = SDL_NumSensors();
|
||||||
|
|
||||||
|
for( int i = 0; i < num_sensors; i++ )
|
||||||
|
{
|
||||||
|
if( SDL_SensorGetDeviceType( i ) == SDL_SENSOR_GYRO )
|
||||||
|
{
|
||||||
|
g_system_gyro = SDL_SensorOpen( i );
|
||||||
|
if( g_system_gyro )
|
||||||
|
{
|
||||||
|
g_system_gyro_id = SDL_SensorGetInstanceID( g_system_gyro );
|
||||||
|
Con_Printf( "SDL: Opened built-in gyroscope: %s\n", SDL_SensorGetName( g_system_gyro ) );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Con_Reportf( S_ERROR "Failed to init SDL Sensor subsystem: %s\n", SDL_GetError() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
==============
|
||||||
|
SDLash_ShutdownSensors
|
||||||
|
|
||||||
|
==============
|
||||||
|
*/
|
||||||
|
void SDLash_ShutdownSensors( void )
|
||||||
|
{
|
||||||
|
if( g_system_gyro )
|
||||||
|
{
|
||||||
|
SDL_SensorClose( g_system_gyro );
|
||||||
|
g_system_gyro = NULL;
|
||||||
|
g_system_gyro_id = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_QuitSubSystem( SDL_INIT_SENSOR );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
==============
|
||||||
|
SDLash_GyroIsAvailable
|
||||||
|
|
||||||
|
==============
|
||||||
|
*/
|
||||||
|
qboolean SDLash_GyroIsAvailable( void )
|
||||||
|
{
|
||||||
|
return ( g_system_gyro != NULL );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
==============
|
||||||
|
SDLash_SensorUpdate
|
||||||
|
|
||||||
|
==============
|
||||||
|
*/
|
||||||
|
void SDLash_SensorUpdate( SDL_SensorEvent sensor )
|
||||||
|
{
|
||||||
|
if( sensor.which == g_system_gyro_id )
|
||||||
|
{
|
||||||
|
IN_GyroEvent( sensor.data );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
void SDLash_InitSensors( void ) { }
|
||||||
|
void SDLash_ShutdownSensors( void ) { }
|
||||||
|
qboolean SDLash_GyroIsAvailable( void ) { return false; }
|
||||||
|
#endif
|
||||||
@@ -146,10 +146,12 @@ void SDLash_Init( void )
|
|||||||
SDL_StopTextInput();
|
SDL_StopTextInput();
|
||||||
|
|
||||||
SDLash_InitCursors();
|
SDLash_InitCursors();
|
||||||
|
SDLash_InitSensors();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SDLash_Shutdown( void )
|
void SDLash_Shutdown( void )
|
||||||
{
|
{
|
||||||
|
SDLash_ShutdownSensors();
|
||||||
SDLash_FreeCursors();
|
SDLash_FreeCursors();
|
||||||
|
|
||||||
SDL_Quit();
|
SDL_Quit();
|
||||||
|
|||||||
@@ -1204,3 +1204,29 @@ void VID_Info_f( void )
|
|||||||
else
|
else
|
||||||
Con_Printf( "Window display mode: " S_RED "fail: " S_DEFAULT "%s\n", SDL_GetError( ));
|
Con_Printf( "Window display mode: " S_RED "fail: " S_DEFAULT "%s\n", SDL_GetError( ));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
platform_orientation_t Platform_GetDisplayOrientation( void )
|
||||||
|
{
|
||||||
|
if( host.hWnd )
|
||||||
|
{
|
||||||
|
int display_index = SDL_GetWindowDisplayIndex( host.hWnd );
|
||||||
|
if( display_index >= 0 )
|
||||||
|
{
|
||||||
|
switch( SDL_GetDisplayOrientation( display_index ) )
|
||||||
|
{
|
||||||
|
case SDL_ORIENTATION_LANDSCAPE:
|
||||||
|
return ORIENTATION_LANDSCAPE;
|
||||||
|
case SDL_ORIENTATION_LANDSCAPE_FLIPPED:
|
||||||
|
return ORIENTATION_LANDSCAPE_FLIPPED;
|
||||||
|
case SDL_ORIENTATION_PORTRAIT:
|
||||||
|
return ORIENTATION_PORTRAIT;
|
||||||
|
case SDL_ORIENTATION_PORTRAIT_FLIPPED:
|
||||||
|
return ORIENTATION_PORTRAIT_FLIPPED;
|
||||||
|
default:
|
||||||
|
return ORIENTATION_UNKNOWN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ORIENTATION_UNKNOWN;
|
||||||
|
}
|
||||||
|
|||||||
@@ -21,8 +21,6 @@ GNU General Public License for more details.
|
|||||||
|
|
||||||
#define GLARE_FALLOFF 19000.0f
|
#define GLARE_FALLOFF 19000.0f
|
||||||
|
|
||||||
static float sprite_radius;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
================
|
================
|
||||||
R_GetSpriteFrameInterpolant
|
R_GetSpriteFrameInterpolant
|
||||||
@@ -212,8 +210,6 @@ static qboolean R_CullSpriteModel( cl_entity_t *e, vec3_t origin )
|
|||||||
VectorScale( e->model->mins, scale, sprite_mins );
|
VectorScale( e->model->mins, scale, sprite_mins );
|
||||||
VectorScale( e->model->maxs, scale, sprite_maxs );
|
VectorScale( e->model->maxs, scale, sprite_maxs );
|
||||||
|
|
||||||
sprite_radius = RadiusFromBounds( sprite_mins, sprite_maxs );
|
|
||||||
|
|
||||||
VectorAdd( sprite_mins, origin, sprite_mins );
|
VectorAdd( sprite_mins, origin, sprite_mins );
|
||||||
VectorAdd( sprite_maxs, origin, sprite_maxs );
|
VectorAdd( sprite_maxs, origin, sprite_maxs );
|
||||||
|
|
||||||
|
|||||||
@@ -224,11 +224,6 @@ static void CL_DrawBeams( int fTrans, BEAM *beams )
|
|||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
static qboolean R_BeamCull( const vec3_t start, const vec3_t end, qboolean pvsOnly )
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int RefGetParm( int parm, int arg )
|
static int RefGetParm( int parm, int arg )
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -21,8 +21,6 @@ GNU General Public License for more details.
|
|||||||
|
|
||||||
#define GLARE_FALLOFF 19000.0f
|
#define GLARE_FALLOFF 19000.0f
|
||||||
|
|
||||||
static float sprite_radius;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
================
|
================
|
||||||
R_CullSpriteModel
|
R_CullSpriteModel
|
||||||
@@ -45,8 +43,6 @@ static qboolean R_CullSpriteModel( cl_entity_t *e, vec3_t origin )
|
|||||||
VectorScale( e->model->mins, scale, sprite_mins );
|
VectorScale( e->model->mins, scale, sprite_mins );
|
||||||
VectorScale( e->model->maxs, scale, sprite_maxs );
|
VectorScale( e->model->maxs, scale, sprite_maxs );
|
||||||
|
|
||||||
sprite_radius = RadiusFromBounds( sprite_mins, sprite_maxs );
|
|
||||||
|
|
||||||
VectorAdd( sprite_mins, origin, sprite_mins );
|
VectorAdd( sprite_mins, origin, sprite_mins );
|
||||||
VectorAdd( sprite_maxs, origin, sprite_maxs );
|
VectorAdd( sprite_maxs, origin, sprite_maxs );
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,8 @@ cd "$GITHUB_WORKSPACE" || die
|
|||||||
cp -vr /Library/Frameworks/SDL2.framework ./build
|
cp -vr /Library/Frameworks/SDL2.framework ./build
|
||||||
|
|
||||||
pushd hlsdk || die
|
pushd hlsdk || die
|
||||||
cmake -DCMAKE_SYSTEM_NAME=iOS -DCMAKE_OSX_DEPLOYMENT_TARGET=12.0 -DGAMEDIR=$(realpath ../build/ios) -DCMAKE_BUILD_TYPE=Debug -B build -S .
|
mkdir -p ../build/ios/libs || die
|
||||||
|
cmake -DCMAKE_SYSTEM_NAME=iOS -DCMAKE_OSX_DEPLOYMENT_TARGET=12.0 -DCMAKE_INSTALL_PREFIX=$(realpath ../build/ios/libs) -DCMAKE_BUILD_TYPE=Debug -B build -S .
|
||||||
cmake --build build --target install || die
|
cmake --build build --target install || die
|
||||||
popd || die
|
popd || die
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user