/* vid_sdl.c - SDL input component Copyright (C) 2018 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. */ #if !XASH_DEDICATED #include #include "common.h" #include "keydefs.h" #include "input.h" #include "client.h" #include "vgui_draw.h" #include "events.h" #include "sound.h" #include "vid_common.h" SDL_Joystick *g_joy = NULL; #if !SDL_VERSION_ATLEAST( 2, 0, 0 ) #define SDL_WarpMouseInWindow( win, x, y ) SDL_WarpMouse( ( x ), ( y ) ) #else static struct { qboolean initialized; SDL_Cursor *cursors[dc_last]; } cursors; #endif /* ============= Platform_GetMousePos ============= */ void GAME_EXPORT Platform_GetMousePos( int *x, int *y ) { SDL_GetMouseState( x, y ); if( x && window_width.value && window_width.value != refState.width ) { float factor = refState.width / window_width.value; *x = *x * factor; } if( y && window_height.value && window_height.value != refState.height ) { float factor = refState.height / window_height.value; *y = *y * factor; } } /* ============= Platform_SetMousePos ============ */ void GAME_EXPORT Platform_SetMousePos( int x, int y ) { SDL_WarpMouseInWindow( host.hWnd, x, y ); } /* ======================== Platform_MouseMove ======================== */ void Platform_MouseMove( float *x, float *y ) { int m_x, m_y; SDL_GetRelativeMouseState( &m_x, &m_y ); *x = (float)m_x; *y = (float)m_y; } /* ============= Platform_GetClipobardText ============= */ int Platform_GetClipboardText( char *buffer, size_t size ) { #if SDL_VERSION_ATLEAST( 2, 0, 0 ) int textLength; char *sdlbuffer = SDL_GetClipboardText(); if( !sdlbuffer ) return 0; if (buffer && size > 0) { textLength = Q_strncpy( buffer, sdlbuffer, size ); } else { textLength = Q_strlen( sdlbuffer ); } SDL_free( sdlbuffer ); return textLength; #else // SDL_VERSION_ATLEAST( 2, 0, 0 ) buffer[0] = 0; #endif // SDL_VERSION_ATLEAST( 2, 0, 0 ) return 0; } /* ============= Platform_SetClipobardText ============= */ void Platform_SetClipboardText( const char *buffer ) { #if SDL_VERSION_ATLEAST( 2, 0, 0 ) SDL_SetClipboardText( buffer ); #endif // SDL_VERSION_ATLEAST( 2, 0, 0 ) } /* ============= Platform_Vibrate ============= */ void Platform_Vibrate( float time, char flags ) { #if SDL_VERSION_ATLEAST( 2, 0, 9 ) if( g_joy ) SDL_JoystickRumble( g_joy, 0xFFFF, 0xFFFF, time * 1000.0f ); #endif // SDL_VERSION_ATLEAST( 2, 0, 9 ) } #if !XASH_PSVITA /* ============= SDLash_EnableTextInput ============= */ void Platform_EnableTextInput( qboolean enable ) { #if SDL_VERSION_ATLEAST( 2, 0, 0 ) enable ? SDL_StartTextInput() : SDL_StopTextInput(); #endif // SDL_VERSION_ATLEAST( 2, 0, 0 ) } #endif // !XASH_PSVITA /* ============= SDLash_JoyInit_Old ============= */ static int SDLash_JoyInit_Old( int numjoy ) { int num; int i; Con_Reportf( "Joystick: SDL\n" ); if( SDL_WasInit( SDL_INIT_JOYSTICK ) != SDL_INIT_JOYSTICK && SDL_InitSubSystem( SDL_INIT_JOYSTICK ) ) { Con_Reportf( "Failed to initialize SDL Joysitck: %s\n", SDL_GetError() ); return 0; } if( g_joy ) { SDL_JoystickClose( g_joy ); } num = SDL_NumJoysticks(); if( num > 0 ) Con_Reportf( "%i joysticks found:\n", num ); else { Con_Reportf( "No joystick found.\n" ); return 0; } #if SDL_VERSION_ATLEAST( 2, 0, 0 ) for( i = 0; i < num; i++ ) Con_Reportf( "%i\t: %s\n", i, SDL_JoystickNameForIndex( i ) ); #endif // SDL_VERSION_ATLEAST( 2, 0, 0 ) Con_Reportf( "Pass +set joy_index N to command line, where N is number, to select active joystick\n" ); g_joy = SDL_JoystickOpen( numjoy ); if( !g_joy ) { Con_Reportf( "Failed to select joystick: %s\n", SDL_GetError( ) ); return 0; } #if SDL_VERSION_ATLEAST( 2, 0, 0 ) Con_Reportf( "Selected joystick: %s\n" "\tAxes: %i\n" "\tHats: %i\n" "\tButtons: %i\n" "\tBalls: %i\n", SDL_JoystickName( g_joy ), SDL_JoystickNumAxes( g_joy ), SDL_JoystickNumHats( g_joy ), SDL_JoystickNumButtons( g_joy ), SDL_JoystickNumBalls( g_joy ) ); SDL_GameControllerEventState( SDL_DISABLE ); #endif // SDL_VERSION_ATLEAST( 2, 0, 0 ) SDL_JoystickEventState( SDL_ENABLE ); return num; } #if SDL_VERSION_ATLEAST( 2, 0, 0 ) /* ============= SDLash_JoyInit_New ============= */ static int SDLash_JoyInit_New( int numjoy ) { int count, numJoysticks, i; Con_Reportf( "Joystick: SDL GameController API\n" ); if( SDL_WasInit( SDL_INIT_GAMECONTROLLER ) != SDL_INIT_GAMECONTROLLER && SDL_InitSubSystem( SDL_INIT_GAMECONTROLLER ) ) { Con_Reportf( "Failed to initialize SDL GameController API: %s\n", SDL_GetError() ); return 0; } SDL_GameControllerAddMappingsFromFile( "controllermappings.txt" ); count = 0; numJoysticks = SDL_NumJoysticks(); for ( i = 0; i < numJoysticks; i++ ) if( SDL_IsGameController( i ) ) ++count; return count; } #endif // SDL_VERSION_ATLEAST( 2, 0, 0 ) /* ============= Platform_JoyInit ============= */ int Platform_JoyInit( int numjoy ) { #if SDL_VERSION_ATLEAST( 2, 0, 0 ) // SDL_Joystick is now an old API // SDL_GameController is preferred if( !Sys_CheckParm( "-sdl_joy_old_api" ) ) return SDLash_JoyInit_New(numjoy); #endif // SDL_VERSION_ATLEAST( 2, 0, 0 ) return SDLash_JoyInit_Old(numjoy); } /* ======================== SDLash_InitCursors ======================== */ void SDLash_InitCursors( void ) { #if SDL_VERSION_ATLEAST( 2, 0, 0 ) if( cursors.initialized ) SDLash_FreeCursors(); // load up all default cursors cursors.cursors[dc_none] = NULL; cursors.cursors[dc_arrow] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW); cursors.cursors[dc_ibeam] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_IBEAM); cursors.cursors[dc_hourglass] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_WAIT); cursors.cursors[dc_crosshair] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_CROSSHAIR); cursors.cursors[dc_up] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW); cursors.cursors[dc_sizenwse] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENWSE); cursors.cursors[dc_sizenesw] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENESW); cursors.cursors[dc_sizewe] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEWE); cursors.cursors[dc_sizens] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENS); cursors.cursors[dc_sizeall] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEALL); cursors.cursors[dc_no] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_NO); cursors.cursors[dc_hand] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_HAND); cursors.initialized = true; #endif } /* ======================== SDLash_FreeCursors ======================== */ void SDLash_FreeCursors( void ) { #if SDL_VERSION_ATLEAST( 2, 0, 0 ) int i = 0; for( ; i < ARRAYSIZE( cursors.cursors ); i++ ) { if( cursors.cursors[i] ) SDL_FreeCursor( cursors.cursors[i] ); cursors.cursors[i] = NULL; } cursors.initialized = false; #endif // SDL_VERSION_ATLEAST( 2, 0, 0 ) } /* ======================== Platform_SetCursorType ======================== */ void Platform_SetCursorType( VGUI_DefaultCursor type ) { qboolean visible; #if SDL_VERSION_ATLEAST( 2, 0, 0 ) if( !cursors.initialized ) return; #endif switch( type ) { case dc_user: case dc_none: visible = false; break; default: visible = true; break; } // never disable cursor in touch emulation mode if( !visible && touch_emulate.value ) return; host.mouse_visible = visible; VGui_UpdateInternalCursorState( type ); #if SDL_VERSION_ATLEAST( 2, 0, 0 ) if( host.mouse_visible ) { SDL_SetCursor( cursors.cursors[type] ); SDL_ShowCursor( true ); } else { SDL_ShowCursor( false ); } #else if( host.mouse_visible ) { SDL_ShowCursor( true ); } else { SDL_ShowCursor( false ); } #endif } /* ======================== Platform_GetKeyModifiers ======================== */ key_modifier_t Platform_GetKeyModifiers( void ) { #if SDL_VERSION_ATLEAST( 2, 0, 0 ) SDL_Keymod modFlags; key_modifier_t resultFlags; resultFlags = KeyModifier_None; modFlags = SDL_GetModState(); if( FBitSet( modFlags, KMOD_LCTRL )) SetBits( resultFlags, KeyModifier_LeftCtrl ); if( FBitSet( modFlags, KMOD_RCTRL )) SetBits( resultFlags, KeyModifier_RightCtrl ); if( FBitSet( modFlags, KMOD_RSHIFT )) SetBits( resultFlags, KeyModifier_RightShift ); if( FBitSet( modFlags, KMOD_LSHIFT )) SetBits( resultFlags, KeyModifier_LeftShift ); if( FBitSet( modFlags, KMOD_LALT )) SetBits( resultFlags, KeyModifier_LeftAlt ); if( FBitSet( modFlags, KMOD_RALT )) SetBits( resultFlags, KeyModifier_RightAlt ); if( FBitSet( modFlags, KMOD_NUM )) SetBits( resultFlags, KeyModifier_NumLock ); if( FBitSet( modFlags, KMOD_CAPS )) SetBits( resultFlags, KeyModifier_CapsLock ); if( FBitSet( modFlags, KMOD_RGUI )) SetBits( resultFlags, KeyModifier_RightSuper ); if( FBitSet( modFlags, KMOD_LGUI )) SetBits( resultFlags, KeyModifier_LeftSuper ); return resultFlags; #else return KeyModifier_None; #endif } #endif // XASH_DEDICATED