This commit is contained in:
FluorescentCIAAfricanAmerican
2020-04-22 12:56:21 -04:00
commit 3bf9df6b27
15370 changed files with 5489726 additions and 0 deletions
+3
View File
@@ -0,0 +1,3 @@
LIBRARY inputsystem_360.dll
EXPORTS
CreateInterface @1
File diff suppressed because it is too large Load Diff
+469
View File
@@ -0,0 +1,469 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//===========================================================================//
#ifndef INPUTSYSTEM_H
#define INPUTSYSTEM_H
#ifdef _WIN32
#pragma once
#endif
#ifdef WIN32
#if !defined( _X360 )
#define _WIN32_WINNT 0x502
#include <windows.h>
#include <zmouse.h>
#include "xbox/xboxstubs.h"
#include "../../dx9sdk/include/XInput.h"
#endif
#endif
#ifdef POSIX
#include "posix_stubs.h"
#endif // POSIX
#include "appframework/ilaunchermgr.h"
#include "inputsystem/iinputsystem.h"
#include "tier2/tier2.h"
#include "inputsystem/ButtonCode.h"
#include "inputsystem/AnalogCode.h"
#include "bitvec.h"
#include "tier1/utlvector.h"
#include "tier1/utlflags.h"
#if defined( _X360 )
#include "xbox/xbox_win32stubs.h"
#include "xbox/xbox_console.h"
#endif
#include "steam/steam_api.h"
//-----------------------------------------------------------------------------
// Implementation of the input system
//-----------------------------------------------------------------------------
class CInputSystem : public CTier2AppSystem< IInputSystem >
{
typedef CTier2AppSystem< IInputSystem > BaseClass;
public:
// Constructor, destructor
CInputSystem();
virtual ~CInputSystem();
// Inherited from IAppSystem
virtual InitReturnVal_t Init();
virtual bool Connect( CreateInterfaceFn factory );
virtual void Shutdown();
// Inherited from IInputSystem
virtual void AttachToWindow( void* hWnd );
virtual void DetachFromWindow();
virtual void EnableInput( bool bEnable );
virtual void EnableMessagePump( bool bEnable );
virtual int GetPollTick() const;
virtual void PollInputState();
virtual bool IsButtonDown( ButtonCode_t code ) const;
virtual int GetButtonPressedTick( ButtonCode_t code ) const;
virtual int GetButtonReleasedTick( ButtonCode_t code ) const;
virtual int GetAnalogValue( AnalogCode_t code ) const;
virtual int GetAnalogDelta( AnalogCode_t code ) const;
virtual int GetEventCount() const;
virtual const InputEvent_t* GetEventData() const;
virtual void PostUserEvent( const InputEvent_t &event );
virtual int GetJoystickCount() const;
virtual void EnableJoystickInput( int nJoystick, bool bEnable );
virtual void EnableJoystickDiagonalPOV( int nJoystick, bool bEnable );
virtual void SampleDevices( void );
virtual void SetRumble( float fLeftMotor, float fRightMotor, int userId );
virtual void StopRumble( void );
virtual void ResetInputState( void );
virtual void SetPrimaryUserId( int userId );
virtual const char *ButtonCodeToString( ButtonCode_t code ) const;
virtual const char *AnalogCodeToString( AnalogCode_t code ) const;
virtual ButtonCode_t StringToButtonCode( const char *pString ) const;
virtual AnalogCode_t StringToAnalogCode( const char *pString ) const;
virtual ButtonCode_t VirtualKeyToButtonCode( int nVirtualKey ) const;
virtual int ButtonCodeToVirtualKey( ButtonCode_t code ) const;
virtual ButtonCode_t ScanCodeToButtonCode( int lParam ) const;
virtual void SleepUntilInput( int nMaxSleepTimeMS );
virtual int GetPollCount() const;
virtual void SetCursorPosition( int x, int y );
#if defined( WIN32 ) && !defined ( _X360 )
virtual void *GetHapticsInterfaceAddress() const;
#else
virtual void *GetHapticsInterfaceAddress() const { return NULL;}
#endif
bool GetRawMouseAccumulators( int& accumX, int& accumY );
virtual void SetConsoleTextMode( bool bConsoleTextMode );
// Windows proc
LRESULT WindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
private:
enum
{
STICK1_AXIS_LEFT,
STICK1_AXIS_RIGHT,
STICK1_AXIS_DOWN,
STICK1_AXIS_UP,
STICK2_AXIS_LEFT,
STICK2_AXIS_RIGHT,
STICK2_AXIS_DOWN,
STICK2_AXIS_UP,
MAX_STICKAXIS
};
// track Xbox stick keys from previous frame
enum
{
LASTKEY_STICK1_X,
LASTKEY_STICK1_Y,
LASTKEY_STICK2_X,
LASTKEY_STICK2_Y,
MAX_LASTKEY,
};
enum
{
INPUT_STATE_QUEUED = 0,
INPUT_STATE_CURRENT,
INPUT_STATE_COUNT,
};
public:
struct JoystickInfo_t
{
void *m_pDevice; // Really an SDL_GameController*, NULL if not present.
void *m_pHaptic; // Really an SDL_Haptic*
float m_fCurrentRumble;
bool m_bRumbleEnabled;
int m_nButtonCount;
int m_nAxisFlags;
int m_nDeviceId;
bool m_bHasPOVControl;
bool m_bDiagonalPOVControlEnabled;
unsigned int m_nFlags;
unsigned int m_nLastPolledButtons;
unsigned int m_nLastPolledAxisButtons;
unsigned int m_nLastPolledPOVState;
unsigned long m_pLastPolledAxes[MAX_JOYSTICK_AXES];
};
struct xdevice_t
{
int userId;
byte type;
byte subtype;
word flags;
bool active;
XINPUT_STATE states[2];
int newState;
xKey_t lastStickKeys[MAX_LASTKEY];
int stickThreshold[MAX_STICKAXIS];
float stickScale[MAX_STICKAXIS];
int quitTimeout;
int dpadLock;
// rumble
XINPUT_VIBRATION vibration;
bool pendingRumbleUpdate;
};
struct appKey_t
{
int repeats;
int sample;
};
struct InputState_t
{
// Analog states
CBitVec<BUTTON_CODE_LAST> m_ButtonState;
int m_ButtonPressedTick[BUTTON_CODE_LAST];
int m_ButtonReleasedTick[BUTTON_CODE_LAST];
int m_pAnalogDelta[ANALOG_CODE_LAST];
int m_pAnalogValue[ANALOG_CODE_LAST];
CUtlVector< InputEvent_t > m_Events;
bool m_bDirty;
};
// Initializes all Xbox controllers
void InitializeXDevices( void );
// Opens an Xbox controller
void OpenXDevice( xdevice_t* pXDevice, int userId );
// Closes an Xbox controller
void CloseXDevice( xdevice_t* pXDevice );
// Samples the Xbox controllers
void PollXDevices( void );
// Samples an Xbox controller and queues input events
void ReadXDevice( xdevice_t* pXDevice );
// Submits force feedback data to an Xbox controller
void WriteToXDevice( xdevice_t* pXDevice );
// Sets rumble values for an Xbox controller
void SetXDeviceRumble( float fLeftMotor, float fRightMotor, int userId );
// Posts an Xbox key event, ignoring key repeats
void PostXKeyEvent( int nUserId, xKey_t xKey, int nSample );
// Dispatches all joystick button events through the game's window procs
void ProcessEvent( UINT uMsg, WPARAM wParam, LPARAM lParam );
// Initializes joysticks
void InitializeJoysticks( void );
// Shut down joysticks
void ShutdownJoysticks( void );
// Samples the joystick
void PollJoystick( void );
// Update the joystick button state
void UpdateJoystickButtonState( int nJoystick );
// Update the joystick POV control
void UpdateJoystickPOVControl( int nJoystick );
// Record button state and post the event
void JoystickButtonEvent( ButtonCode_t button, int sample );
#if defined( WIN32 ) && !defined ( _X360 )
// NVNT attaches window to novint devices
void AttachWindowToNovintDevices( void * hWnd );
// NVNT detaches window from novint input
void DetachWindowFromNovintDevices( void );
// NVNT Initializes novint devices
void InitializeNovintDevices( void );
// NVNT Samples a novint device
void PollNovintDevices( void );
// NVNT Update the novint device button state
void UpdateNovintDeviceButtonState( int nDevice );
// NVNT Record button state and post the event
void NovintDeviceButtonEvent( ButtonCode_t button, int sample );
//Added called and set to true when binding input and set to false once bound
void SetNovintPure( bool bPure );
#else
void SetNovintPure( bool bPure ) {} // to satify the IInput virtual interface
#endif
// Chains the window message to the previous wndproc
LRESULT ChainWindowMessage( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
// Post an event to the queue
void PostEvent( int nType, int nTick, int nData = 0, int nData2 = 0, int nData3 = 0 );
// Deals with app deactivation (sends a bunch of button released messages)
void ActivateInputSystem( bool bActivated );
// Determines all mouse button presses
int ButtonMaskFromMouseWParam( WPARAM wParam, ButtonCode_t code = BUTTON_CODE_INVALID, bool bDown = false ) const;
// Updates the state of all mouse buttons
void UpdateMouseButtonState( int nButtonMask, ButtonCode_t dblClickCode = BUTTON_CODE_INVALID );
// Copies the input state record over
void CopyInputState( InputState_t *pDest, const InputState_t &src, bool bCopyEvents );
// Post an button press/release event to the queue
void PostButtonPressedEvent( InputEventType_t nType, int nTick, ButtonCode_t scanCode, ButtonCode_t virtualCode );
void PostButtonReleasedEvent( InputEventType_t nType, int nTick, ButtonCode_t scanCode, ButtonCode_t virtualCode );
// Release all buttons
void ReleaseAllButtons( int nFirstButton = 0, int nLastButton = BUTTON_CODE_LAST - 1 );
// Zero analog state
void ZeroAnalogState( int nFirstState, int nLastState );
// Converts xbox keys to button codes
ButtonCode_t XKeyToButtonCode( int nUserId, int nXKey ) const;
// Computes the sample tick
int ComputeSampleTick();
// Clears the input state, doesn't generate key-up messages
void ClearInputState();
// Called for mouse move events. Sets the current x and y and posts events for the mouse moving.
void UpdateMousePositionState( InputState_t &state, short x, short y );
// Initializes SteamControllers - Returns true if steam is running and finds controllers, otherwise false
bool InitializeSteamControllers( void );
// Returns number of connected Steam Controllers
uint32 GetNumSteamControllersConnected();
// Update and sample steam controllers
void PollSteamControllers( void );
#if defined( PLATFORM_WINDOWS_PC )
void PollInputState_Windows();
#endif
void JoystickHotplugAdded( int joystickIndex );
void JoystickHotplugRemoved( int joystickId );
void JoystickButtonPress( int joystickId, int button ); // button is a SDL_CONTROLLER_BUTTON;
void JoystickButtonRelease( int joystickId, int button ); // same as above.
void JoystickAxisMotion( int joystickId, int axis, int value );
// Steam Controller
void ReadSteamController( int iIndex );
void PostKeyEvent( int iIndex, sKey_t sKey, int nSample );
const int GetSteamPadDeadZone( ESteamPadAxis axis );
bool IsSteamControllerConnected( void ) { return m_bSteamController; }
bool IsSteamControllerActive( void );
void ActivateSteamControllerActionSetForSlot( uint64 nSlot, GameActionSet_t eActionSet );
ControllerActionSetHandle_t GetActionSetHandle( GameActionSet_t eActionSet );
ControllerActionSetHandle_t GetActionSetHandle( const char* szActionSet );
bool GetControllerStateForSlot( int nSlot );
int GetSteamControllerIndexForSlot( int nSlot );
bool GetRadialMenuStickValues( int nSlot, float &fX, float &fY );
virtual ISteamController* SteamControllerInterface();
bool InitializeSteamControllerActionSets();
// Gets the action origin (i.e. which physical input) maps to the given action name
virtual EControllerActionOrigin GetSteamControllerActionOrigin( const char* action, GameActionSet_t action_set );
virtual EControllerActionOrigin GetSteamControllerActionOrigin( const char* action, ControllerActionSetHandle_t action_set_handle );
// Maps a Steam Controller action origin to a string (consisting of a single character) in our SC icon font
virtual const wchar_t* GetSteamControllerFontCharacterForActionOrigin( EControllerActionOrigin origin );
// Maps a Steam Controller action origin to a short text string (e.g. "X", "LB", "LDOWN") describing the control.
// Prefer to actually use the icon font wherever possible.
virtual const wchar_t* GetSteamControllerDescriptionForActionOrigin( EControllerActionOrigin origin );
// Converts SteamController keys to button codes
ButtonCode_t SKeyToButtonCode( int nUserId, int nXKey ) const;
// This is called with "true" by dedicated server initialization (before calling Init) in order to
// force us to skip initialization of Steam (which messes up dedicated servers).
virtual void SetSkipControllerInitialization( bool bSkip )
{
m_bSkipControllerInitialization = bSkip;
}
#if defined( USE_SDL )
void PollInputState_Platform();
ILauncherMgr *m_pLauncherMgr;
#endif
WNDPROC m_ChainedWndProc;
HWND m_hAttachedHWnd;
bool m_bEnabled;
bool m_bPumpEnabled;
bool m_bIsPolling;
// Current button state
InputState_t m_InputState[INPUT_STATE_COUNT];
// Current action set
GameActionSet_t m_currentActionSet[STEAM_CONTROLLER_MAX_COUNT];
DWORD m_StartupTimeTick;
int m_nLastPollTick;
int m_nLastSampleTick;
int m_nPollCount;
// Mouse wheel hack
UINT m_uiMouseWheel;
// Joystick info
CUtlFlags<unsigned short> m_JoysticksEnabled;
int m_nJoystickCount;
bool m_bJoystickInitialized;
bool m_bXController;
JoystickInfo_t m_pJoystickInfo[ MAX_JOYSTICKS ];
// Steam Controller
struct steampad_t
{
steampad_t()
{
m_nHardwareIndex = 0;
m_nJoystickIndex = INVALID_USER_ID;
m_nLastPacketIndex = 0;
active = false;
memset( lastAnalogKeys, 0, sizeof( lastAnalogKeys ) );
}
bool active;
sKey_t lastAnalogKeys[MAX_STEAMPADAXIS];
appKey_t m_appSKeys[SK_MAX_KEYS];
// Hardware index and joystick index don't necessarily match
// Joystick index will depend on the order of multiple initialized devices
// Which could include other controller types
// Hardware index should line up 1:1 with the order they're polled
// and could change based on removing devices, unlike Joystick Index
uint32 m_nHardwareIndex;
int m_nJoystickIndex;
uint32 m_nLastPacketIndex;
};
float m_pRadialMenuStickVal[STEAM_CONTROLLER_MAX_COUNT][2];
steampad_t m_Device[STEAM_CONTROLLER_MAX_COUNT];
uint32 m_unNumConnected;
float m_flLastSteamControllerInput;
int m_nJoystickBaseline;
int m_nControllerType[MAX_JOYSTICKS+STEAM_CONTROLLER_MAX_COUNT];
bool m_bSteamController; // true if the Steam Controller system has been initialized successfully (this doesn't mean one is actually connected necessarily)
bool m_bSteamControllerActionsInitialized; // true if our action sets and handles were successfully initialized (this doesn't mean a controller is necessarily connected, or that in-game client actions were initialized)
bool m_bSteamControllerActive; // true if our action sets and handles were successfully initialized *and* that at least one controller is actually connected and switched on.
#if defined( WIN32 ) && !defined ( _X360 )
// NVNT Novint device info
int m_nNovintDeviceCount;
bool m_bNovintDevices;
#endif
// Xbox controller info
appKey_t m_appXKeys[ XUSER_MAX_COUNT ][ XK_MAX_KEYS ];
xdevice_t m_XDevices[ XUSER_MAX_COUNT ];
int m_PrimaryUserId;
// raw mouse input
bool m_bRawInputSupported;
int m_mouseRawAccumX, m_mouseRawAccumY;
// For the 'SleepUntilInput' feature
HANDLE m_hEvent;
CSysModule *m_pXInputDLL;
CSysModule *m_pRawInputDLL;
#if defined( WIN32 ) && !defined ( _X360 )
// NVNT falcon module
CSysModule *m_pNovintDLL;
#endif
bool m_bConsoleTextMode;
public:
// Steam API context for use by input system for access to steam controllers.
CSteamAPIContext& SteamAPIContext() { return m_SteamAPIContext; }
private:
CSteamAPIContext m_SteamAPIContext;
bool m_bSkipControllerInitialization;
};
#endif // INPUTSYSTEM_H
+55
View File
@@ -0,0 +1,55 @@
//-----------------------------------------------------------------------------
// INPUTSYSTEM.VPC
//
// Project Script
//-----------------------------------------------------------------------------
$macro SRCDIR ".."
$Macro OUTBINDIR "$SRCDIR\..\game\bin"
$include "$SRCDIR\vpc_scripts\source_dll_base.vpc"
$Configuration
{
$Compiler
{
$AdditionalIncludeDirectories "$BASE;$SRCDIR\thirdparty\SDL2" [!$SDL] // If $SDL, then we already have this from source_video_base.vpc.
$PreprocessorDefinitions "$BASE;VERSION_SAFE_STEAM_API_INTERFACES"
}
$Linker
{
$SystemLibraries "iconv" [$OSXALL]
$SystemFrameworks "IOKit;Carbon;ForceFeedback"
}
}
$Project "inputsystem"
{
$Folder "Source Files"
{
$File "inputsystem.cpp"
$File "inputsystem.h"
$File "joystick_sdl.cpp"
$File "novint.cpp" [$WIN32]
$File "key_translation.cpp"
$File "key_translation.h"
$File "steamcontroller.cpp"
}
$Folder "Public Headers"
{
$File "$SRCDIR\public\inputsystem\AnalogCode.h"
$File "$SRCDIR\public\inputsystem\ButtonCode.h"
$File "$SRCDIR\public\inputsystem\iinputsystem.h"
$File "$SRCDIR\public\inputsystem\InputEnums.h"
$File "$SRCDIR\dx9sdk\include\xinput.h" [$WIN32]
}
$Folder "Link Libraries"
{
$Lib tier1
$Lib tier2
$ImpLib SDL2
$Implib "steam_api" [($WIN32||$WIN64||$POSIX||$PS3)&&!$NO_STEAM]
}
}
+615
View File
@@ -0,0 +1,615 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Linux Joystick implementation for inputsystem.dll
//
//===========================================================================//
/* For force feedback testing. */
#include "inputsystem.h"
#include "tier1/convar.h"
#include "tier0/icommandline.h"
#include "SDL.h"
#include "SDL_gamecontroller.h"
#include "SDL_haptic.h"
// NOTE: This has to be the last file included!
#include "tier0/memdbgon.h"
static ButtonCode_t ControllerButtonToButtonCode( SDL_GameControllerButton button );
static AnalogCode_t ControllerAxisToAnalogCode( SDL_GameControllerAxis axis );
static int JoystickSDLWatcher( void *userInfo, SDL_Event *event );
ConVar joy_axisbutton_threshold( "joy_axisbutton_threshold", "0.3", FCVAR_ARCHIVE, "Analog axis range before a button press is registered." );
ConVar joy_axis_deadzone( "joy_axis_deadzone", "0.2", FCVAR_ARCHIVE, "Dead zone near the zero point to not report movement." );
static void joy_active_changed_f( IConVar *var, const char *pOldValue, float flOldValue );
ConVar joy_active( "joy_active", "-1", FCVAR_NONE, "Which of the connected joysticks / gamepads to use (-1 means first found)", &joy_active_changed_f);
static void joy_gamecontroller_config_changed_f( IConVar *var, const char *pOldValue, float flOldValue );
ConVar joy_gamecontroller_config( "joy_gamecontroller_config", "", FCVAR_ARCHIVE, "Game controller mapping (passed to SDL with SDL_HINT_GAMECONTROLLERCONFIG), can also be configured in Steam Big Picture mode.", &joy_gamecontroller_config_changed_f );
void SearchForDevice()
{
int newJoystickId = joy_active.GetInt();
CInputSystem *pInputSystem = (CInputSystem *)g_pInputSystem;
if ( !pInputSystem )
{
return;
}
// -1 means "first available."
if ( newJoystickId < 0 )
{
pInputSystem->JoystickHotplugAdded(0);
return;
}
for ( int device_index = 0; device_index < SDL_NumJoysticks(); ++device_index )
{
SDL_Joystick *joystick = SDL_JoystickOpen(device_index);
if ( joystick == NULL )
{
continue;
}
int joystickId = SDL_JoystickInstanceID(joystick);
SDL_JoystickClose(joystick);
if ( joystickId == newJoystickId )
{
pInputSystem->JoystickHotplugAdded(device_index);
break;
}
}
}
//---------------------------------------------------------------------------------------
// Switch our active joystick to another device
//---------------------------------------------------------------------------------------
void joy_active_changed_f( IConVar *var, const char *pOldValue, float flOldValue )
{
SearchForDevice();
}
//---------------------------------------------------------------------------------------
// Reinitialize the game controller layer when the joy_gamecontroller_config is updated.
//---------------------------------------------------------------------------------------
void joy_gamecontroller_config_changed_f( IConVar *var, const char *pOldValue, float flOldValue )
{
CInputSystem *pInputSystem = (CInputSystem *)g_pInputSystem;
if ( pInputSystem && SDL_WasInit(SDL_INIT_GAMECONTROLLER) )
{
bool oldValuePresent = pOldValue && ( strlen( pOldValue ) > 0 );
bool newValuePresent = ( strlen( joy_gamecontroller_config.GetString() ) > 0 );
if ( !oldValuePresent && !newValuePresent )
{
return;
}
// We need to reinitialize the whole thing (i.e. undo CInputSystem::InitializeJoysticks and then call it again)
// due to SDL_GameController only reading the SDL_HINT_GAMECONTROLLERCONFIG on init.
pInputSystem->ShutdownJoysticks();
pInputSystem->InitializeJoysticks();
}
}
//-----------------------------------------------------------------------------
// Handle the events coming from the GameController SDL subsystem.
//-----------------------------------------------------------------------------
int JoystickSDLWatcher( void *userInfo, SDL_Event *event )
{
CInputSystem *pInputSystem = (CInputSystem *)userInfo;
Assert(pInputSystem != NULL);
Assert(event != NULL);
if ( event == NULL || pInputSystem == NULL )
{
Warning("No input system\n");
return 1;
}
switch ( event->type )
{
case SDL_CONTROLLERAXISMOTION:
case SDL_CONTROLLERBUTTONDOWN:
case SDL_CONTROLLERBUTTONUP:
case SDL_CONTROLLERDEVICEADDED:
case SDL_CONTROLLERDEVICEREMOVED:
break;
default:
return 1;
}
// This is executed on the same thread as SDL_PollEvent, as PollEvent
// updates the joystick subsystem, which then calls SDL_PushEvent for
// the various events below. PushEvent invokes this callback.
// SDL_PollEvent is called in PumpWindowsMessageLoop which is coming
// from PollInputState_Linux, so there's no worry about calling
// PostEvent (which doesn't seem to be thread safe) from other threads.
Assert(ThreadInMainThread());
switch ( event->type )
{
case SDL_CONTROLLERAXISMOTION:
{
pInputSystem->JoystickAxisMotion(event->caxis.which, event->caxis.axis, event->caxis.value);
break;
}
case SDL_CONTROLLERBUTTONDOWN:
pInputSystem->JoystickButtonPress(event->cbutton.which, event->cbutton.button);
break;
case SDL_CONTROLLERBUTTONUP:
pInputSystem->JoystickButtonRelease(event->cbutton.which, event->cbutton.button);
break;
case SDL_CONTROLLERDEVICEADDED:
pInputSystem->JoystickHotplugAdded(event->cdevice.which);
break;
case SDL_CONTROLLERDEVICEREMOVED:
pInputSystem->JoystickHotplugRemoved(event->cdevice.which);
SearchForDevice();
break;
}
return 1;
}
//-----------------------------------------------------------------------------
// Initialize all joysticks
//-----------------------------------------------------------------------------
void CInputSystem::InitializeJoysticks( void )
{
if ( m_bJoystickInitialized )
{
ShutdownJoysticks();
}
// assume no joystick
m_nJoystickCount = 0;
memset( m_pJoystickInfo, 0, sizeof( m_pJoystickInfo ) );
for ( int i = 0; i < MAX_JOYSTICKS; ++i )
{
m_pJoystickInfo[ i ].m_nDeviceId = -1;
}
// abort startup if user requests no joystick
if ( CommandLine()->FindParm("-nojoy") ) return;
const char *controllerConfig = joy_gamecontroller_config.GetString();
if ( strlen(controllerConfig) > 0 )
{
DevMsg("Passing joy_gamecontroller_config to SDL ('%s').\n", controllerConfig);
// We need to pass this hint to SDL *before* we init the gamecontroller subsystem, otherwise it gets ignored.
SDL_SetHint(SDL_HINT_GAMECONTROLLERCONFIG, controllerConfig);
}
if ( SDL_InitSubSystem( SDL_INIT_GAMECONTROLLER | SDL_INIT_HAPTIC ) == -1 )
{
Warning("Joystick init failed -- SDL_Init(SDL_INIT_GAMECONTROLLER|SDL_INIT_HAPTIC) failed: %s.\n", SDL_GetError());
return;
}
m_bJoystickInitialized = true;
SDL_AddEventWatch(JoystickSDLWatcher, this);
const int totalSticks = SDL_NumJoysticks();
for ( int i = 0; i < totalSticks; i++ )
{
if ( SDL_IsGameController(i) )
{
JoystickHotplugAdded(i);
}
else
{
SDL_JoystickGUID joyGUID = SDL_JoystickGetDeviceGUID(i);
char szGUID[sizeof(joyGUID.data)*2 + 1];
SDL_JoystickGetGUIDString(joyGUID, szGUID, sizeof(szGUID));
Msg("Found joystick '%s' (%s), but no recognized controller configuration for it.\n", SDL_JoystickNameForIndex(i), szGUID);
}
}
if ( totalSticks < 1 )
{
Msg("Did not detect any valid joysticks.\n");
}
}
void CInputSystem::ShutdownJoysticks()
{
if ( !m_bJoystickInitialized )
{
return;
}
SDL_DelEventWatch( JoystickSDLWatcher, this );
if ( m_pJoystickInfo[ 0 ].m_pDevice != NULL )
{
JoystickHotplugRemoved( m_pJoystickInfo[ 0 ].m_nDeviceId );
}
SDL_QuitSubSystem( SDL_INIT_GAMECONTROLLER | SDL_INIT_HAPTIC );
m_bJoystickInitialized = false;
}
// Update the joy_xcontroller_found convar to force CInput::JoyStickMove to re-exec 360controller-linux.cfg
static void SetJoyXControllerFound( bool found )
{
static ConVarRef xcontrollerVar( "joy_xcontroller_found" );
static ConVarRef joystickVar( "joystick" );
if ( xcontrollerVar.IsValid() )
{
xcontrollerVar.SetValue(found);
}
if ( found && joystickVar.IsValid() )
{
joystickVar.SetValue(true);
}
}
void CInputSystem::JoystickHotplugAdded( int joystickIndex )
{
// SDL_IsGameController doesn't bounds check its inputs.
if ( joystickIndex < 0 || joystickIndex >= SDL_NumJoysticks() )
{
return;
}
if ( !SDL_IsGameController(joystickIndex) )
{
Warning("Joystick is not recognized by the game controller system. You can configure the controller in Steam Big Picture mode.\n");
return;
}
SDL_Joystick *joystick = SDL_JoystickOpen(joystickIndex);
if ( joystick == NULL )
{
Warning("Could not open joystick %i: %s", joystickIndex, SDL_GetError());
return;
}
int joystickId = SDL_JoystickInstanceID(joystick);
SDL_JoystickClose(joystick);
int activeJoystick = joy_active.GetInt();
JoystickInfo_t& info = m_pJoystickInfo[ 0 ];
if ( activeJoystick < 0 )
{
// Only opportunistically open devices if we don't have one open already.
if ( info.m_nDeviceId != -1 )
{
Msg("Detected supported joystick #%i '%s'. Currently active joystick is #%i.\n", joystickId, SDL_JoystickNameForIndex(joystickIndex), info.m_nDeviceId);
return;
}
}
else if ( activeJoystick != joystickId )
{
Msg("Detected supported joystick #%i '%s'. Currently active joystick is #%i.\n", joystickId, SDL_JoystickNameForIndex(joystickIndex), activeJoystick);
return;
}
if ( info.m_nDeviceId != -1 )
{
// Don't try to open the device we already have open.
if ( info.m_nDeviceId == joystickId )
{
return;
}
DevMsg("Joystick #%i already initialized, removing it first.\n", info.m_nDeviceId);
JoystickHotplugRemoved(info.m_nDeviceId);
}
Msg("Initializing joystick #%i and making it active.\n", joystickId);
SDL_GameController *controller = SDL_GameControllerOpen(joystickIndex);
if ( controller == NULL )
{
Warning("Failed to open joystick %i: %s\n", joystickId, SDL_GetError());
return;
}
// XXX: This will fail if this is a *real* hotplug event (and not coming from the initial InitializeJoysticks call).
// That's because the SDL haptic subsystem currently doesn't do hotplugging. Everything but haptics will work fine.
SDL_Haptic *haptic = SDL_HapticOpenFromJoystick(SDL_GameControllerGetJoystick(controller));
if ( haptic == NULL || SDL_HapticRumbleInit(haptic) != 0 )
{
Warning("Unable to initialize rumble for joystick #%i: %s\n", joystickId, SDL_GetError());
haptic = NULL;
}
info.m_pDevice = controller;
info.m_pHaptic = haptic;
info.m_nDeviceId = SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(controller));
info.m_nButtonCount = SDL_CONTROLLER_BUTTON_MAX;
info.m_bRumbleEnabled = false;
SetJoyXControllerFound(true);
EnableJoystickInput(0, true);
m_nJoystickCount = 1;
m_bXController = true;
// We reset joy_active to -1 because joystick ids are never reused - until you restart.
// Setting it to -1 means that you get expected hotplugging behavior if you disconnect the current joystick.
joy_active.SetValue(-1);
}
void CInputSystem::JoystickHotplugRemoved( int joystickId )
{
JoystickInfo_t& info = m_pJoystickInfo[ 0 ];
if ( info.m_nDeviceId != joystickId )
{
DevMsg("Ignoring hotplug remove for #%i, active joystick is #%i.\n", joystickId, info.m_nDeviceId);
return;
}
if ( info.m_pDevice == NULL )
{
info.m_nDeviceId = -1;
DevMsg("Got hotplug remove event for removed joystick #%i, ignoring.\n", joystickId);
return;
}
m_nJoystickCount = 0;
m_bXController = false;
EnableJoystickInput(0, false);
SetJoyXControllerFound(false);
SDL_HapticClose((SDL_Haptic *)info.m_pHaptic);
SDL_GameControllerClose((SDL_GameController *)info.m_pDevice);
info.m_pHaptic = NULL;
info.m_pDevice = NULL;
info.m_nButtonCount = 0;
info.m_nDeviceId = -1;
info.m_bRumbleEnabled = false;
Msg("Joystick %i removed.\n", joystickId);
}
void CInputSystem::JoystickButtonPress( int joystickId, int button )
{
JoystickInfo_t& info = m_pJoystickInfo[ 0 ];
if ( info.m_nDeviceId != joystickId )
{
Warning("Not active device input system (%i x %i)\n", info.m_nDeviceId, joystickId);
return;
}
ButtonCode_t buttonCode = ControllerButtonToButtonCode((SDL_GameControllerButton)button);
PostButtonPressedEvent(IE_ButtonPressed, m_nLastSampleTick, buttonCode, buttonCode);
}
void CInputSystem::JoystickButtonRelease( int joystickId, int button )
{
JoystickInfo_t& info = m_pJoystickInfo[ 0 ];
if ( info.m_nDeviceId != joystickId )
{
return;
}
ButtonCode_t buttonCode = ControllerButtonToButtonCode((SDL_GameControllerButton)button);
PostButtonReleasedEvent(IE_ButtonReleased, m_nLastSampleTick, buttonCode, buttonCode);
}
void CInputSystem::JoystickAxisMotion( int joystickId, int axis, int value )
{
JoystickInfo_t& info = m_pJoystickInfo[ 0 ];
if ( info.m_nDeviceId != joystickId )
{
return;
}
AnalogCode_t code = ControllerAxisToAnalogCode((SDL_GameControllerAxis)axis);
if ( code == ANALOG_CODE_INVALID )
{
Warning("Invalid code for axis %i\n", axis);
return;
}
ButtonCode_t buttonCode = BUTTON_CODE_NONE;
switch ( axis )
{
case SDL_CONTROLLER_AXIS_TRIGGERRIGHT:
buttonCode = KEY_XBUTTON_RTRIGGER;
break;
case SDL_CONTROLLER_AXIS_TRIGGERLEFT:
buttonCode = KEY_XBUTTON_LTRIGGER;
break;
}
if ( buttonCode != BUTTON_CODE_NONE )
{
int pressThreshold = joy_axisbutton_threshold.GetFloat() * 32767;
int keyIndex = buttonCode - KEY_XBUTTON_LTRIGGER;
Assert( keyIndex < ARRAYSIZE( m_appXKeys[0] ) && keyIndex >= 0 );
appKey_t &key = m_appXKeys[0][keyIndex];
if ( value > pressThreshold )
{
if ( key.repeats < 1 )
{
PostButtonPressedEvent( IE_ButtonPressed, m_nLastSampleTick, buttonCode, buttonCode );
}
key.repeats++;
}
else
{
PostButtonReleasedEvent( IE_ButtonReleased, m_nLastSampleTick, buttonCode, buttonCode );
key.repeats = 0;
}
}
int minValue = joy_axis_deadzone.GetFloat() * 32767;
if ( abs(value) < minValue )
{
value = 0;
}
InputState_t& state = m_InputState[ m_bIsPolling ];
state.m_pAnalogDelta[ code ] = value - state.m_pAnalogValue[ code ];
state.m_pAnalogValue[ code ] = value;
if ( state.m_pAnalogDelta[ code ] != 0 )
{
PostEvent(IE_AnalogValueChanged, m_nLastSampleTick, code, value, 0);
}
}
//-----------------------------------------------------------------------------
// Process the event
//-----------------------------------------------------------------------------
void CInputSystem::JoystickButtonEvent( ButtonCode_t button, int sample )
{
// Not used - we post button events from JoystickButtonPress/Release.
}
//-----------------------------------------------------------------------------
// Update the joystick button state
//-----------------------------------------------------------------------------
void CInputSystem::UpdateJoystickButtonState( int nJoystick )
{
// We don't sample - we get events posted by SDL_GameController in JoystickSDLWatcher
}
//-----------------------------------------------------------------------------
// Update the joystick POV control
//-----------------------------------------------------------------------------
void CInputSystem::UpdateJoystickPOVControl( int nJoystick )
{
// SDL GameController does not support joystick POV. Should we poll?
}
//-----------------------------------------------------------------------------
// Purpose: Sample the joystick
//-----------------------------------------------------------------------------
void CInputSystem::PollJoystick( void )
{
// We only pump the SDL event loop if we're not an SDL app, since otherwise PollInputState_Platform calls into CSDLMgr to pump it.
// Our state updates happen in events posted by SDL_GameController in JoystickSDLWatcher, so the loop is empty.
#if !defined( USE_SDL )
SDL_Event event;
int nEventsProcessed = 0;
SDL_PumpEvents();
while ( SDL_PollEvent( &event ) && nEventsProcessed < 100 )
{
nEventsProcessed++;
}
#endif
}
void CInputSystem::SetXDeviceRumble( float fLeftMotor, float fRightMotor, int userId )
{
JoystickInfo_t& info = m_pJoystickInfo[ 0 ];
if ( info.m_nDeviceId < 0 || info.m_pHaptic == NULL )
{
return;
}
float strength = (fLeftMotor + fRightMotor) / 2.f;
static ConVarRef joystickVar( "joystick" );
// 0f means "stop".
bool shouldStop = ( strength < 0.01f );
// If they've disabled the gamecontroller in settings, never rumble.
if ( !joystickVar.IsValid() || !joystickVar.GetBool() )
{
shouldStop = true;
}
if ( shouldStop )
{
if ( info.m_bRumbleEnabled )
{
SDL_HapticRumbleStop( (SDL_Haptic *)info.m_pHaptic );
info.m_bRumbleEnabled = false;
info.m_fCurrentRumble = 0.0f;
}
return;
}
// If there's little change, then don't change the rumble strength.
if ( info.m_bRumbleEnabled && abs(info.m_fCurrentRumble - strength) < 0.01f )
{
return;
}
info.m_bRumbleEnabled = true;
info.m_fCurrentRumble = strength;
if ( SDL_HapticRumblePlay((SDL_Haptic *)info.m_pHaptic, strength, SDL_HAPTIC_INFINITY) != 0 )
{
Warning("Couldn't play rumble (strength %.1f): %s\n", strength, SDL_GetError());
}
}
ButtonCode_t ControllerButtonToButtonCode( SDL_GameControllerButton button )
{
switch ( button )
{
case SDL_CONTROLLER_BUTTON_A: // KEY_XBUTTON_A
case SDL_CONTROLLER_BUTTON_B: // KEY_XBUTTON_B
case SDL_CONTROLLER_BUTTON_X: // KEY_XBUTTON_X
case SDL_CONTROLLER_BUTTON_Y: // KEY_XBUTTON_Y
return JOYSTICK_BUTTON(0, button);
case SDL_CONTROLLER_BUTTON_BACK:
return KEY_XBUTTON_BACK;
case SDL_CONTROLLER_BUTTON_START:
return KEY_XBUTTON_START;
case SDL_CONTROLLER_BUTTON_GUIDE:
return KEY_XBUTTON_BACK; // XXX: How are we supposed to handle this? Steam overlay etc.
case SDL_CONTROLLER_BUTTON_LEFTSTICK:
return KEY_XBUTTON_STICK1;
case SDL_CONTROLLER_BUTTON_RIGHTSTICK:
return KEY_XBUTTON_STICK2;
case SDL_CONTROLLER_BUTTON_LEFTSHOULDER:
return KEY_XBUTTON_LEFT_SHOULDER;
case SDL_CONTROLLER_BUTTON_RIGHTSHOULDER:
return KEY_XBUTTON_RIGHT_SHOULDER;
case SDL_CONTROLLER_BUTTON_DPAD_UP:
return KEY_XBUTTON_UP;
case SDL_CONTROLLER_BUTTON_DPAD_DOWN:
return KEY_XBUTTON_DOWN;
case SDL_CONTROLLER_BUTTON_DPAD_LEFT:
return KEY_XBUTTON_LEFT;
case SDL_CONTROLLER_BUTTON_DPAD_RIGHT:
return KEY_XBUTTON_RIGHT;
}
return BUTTON_CODE_NONE;
}
AnalogCode_t ControllerAxisToAnalogCode( SDL_GameControllerAxis axis )
{
switch ( axis )
{
case SDL_CONTROLLER_AXIS_LEFTX:
return JOYSTICK_AXIS(0, JOY_AXIS_X);
case SDL_CONTROLLER_AXIS_LEFTY:
return JOYSTICK_AXIS(0, JOY_AXIS_Y);
case SDL_CONTROLLER_AXIS_RIGHTX:
return JOYSTICK_AXIS(0, JOY_AXIS_U);
case SDL_CONTROLLER_AXIS_RIGHTY:
return JOYSTICK_AXIS(0, JOY_AXIS_R);
case SDL_CONTROLLER_AXIS_TRIGGERRIGHT:
case SDL_CONTROLLER_AXIS_TRIGGERLEFT:
return JOYSTICK_AXIS(0, JOY_AXIS_Z);
}
return ANALOG_CODE_INVALID;
}
+911
View File
@@ -0,0 +1,911 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//===========================================================================//
#if defined( WIN32 )
#if !defined( _X360 )
#include <wtypes.h>
#include <winuser.h>
#include "xbox/xboxstubs.h"
#else
#include "xbox/xbox_win32stubs.h"
#endif
#endif // WIN32
#include "key_translation.h"
#include "tier1/convar.h"
#include "tier1/strtools.h"
#include "tier0/dbg.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
#if defined(__clang__)
#pragma GCC diagnostic ignored "-Wchar-subscripts"
#endif
static ButtonCode_t s_pVirtualKeyToButtonCode[256];
static ButtonCode_t s_pSKeytoButtonCode[SK_MAX_KEYS];
#if !defined( POSIX )
static ButtonCode_t s_pXKeyTrans[XK_MAX_KEYS];
#endif
#define SCONTROLLERBUTTONS_BUTTONS( x ) \
"SC_A",\
"SC_B",\
"SC_X",\
"SC_Y",\
"SC_DPAD_UP",\
"SC_DPAD_RIGHT",\
"SC_DPAD_DOWN",\
"SC_DPAD_LEFT",\
"SC_LEFT_BUMPER",\
"SC_RIGHT_BUMPER",\
"SC_LEFT_TRIGGER",\
"SC_RIGHT_TRIGGER",\
"SC_LEFT_GRIP",\
"SC_RIGHT_GRIP",\
"SC_LEFT_PAD_TOUCH",\
"SC_RIGHT_PAD_TOUCH",\
"SC_LEFT_PAD_CLICK",\
"SC_RIGHT_PAD_CLICK",\
"SC_LPAD_UP",\
"SC_LPAD_RIGHT",\
"SC_LPAD_DOWN",\
"SC_LPAD_LEFT",\
"SC_RPAD_UP",\
"SC_RPAD_RIGHT",\
"SC_RPAD_DOWN",\
"SC_RPAD_LEFT",\
"SC_SELECT",\
"SC_START",\
"SC_STEAM",\
"SC_NULL"
#define SCONTROLLERBUTTONS_AXIS( x ) \
"SC_LPAD_AXIS_RIGHT",\
"SC_LPAD_AXIS_LEFT",\
"SC_LPAD_AXIS_DOWN",\
"SC_LPAD_AXIS_UP",\
"SC_AXIS_L_TRIGGER",\
"SC_AXIS_R_TRIGGER",\
"SC_RPAD_AXIS_RIGHT",\
"SC_RPAD_AXIS_LEFT",\
"SC_RPAD_AXIS_DOWN",\
"SC_RPAD_AXIS_UP",\
"SC_GYRO_AXIS_PITCH_POSITIVE",\
"SC_GYRO_AXIS_PITCH_NEGATIVE",\
"SC_GYRO_AXIS_ROLL_POSITIVE",\
"SC_GYRO_AXIS_ROLL_NEGATIVE",\
"SC_GYRO_AXIS_YAW_POSITIVE",\
"SC_GYRO_AXIS_YAW_NEGATIVE"
#define SCONTROLLERBUTTONS_VBUTTONS( x ) \
"SC_F1",\
"SC_F2",\
"SC_F3",\
"SC_F4",\
"SC_F5",\
"SC_F6",\
"SC_F7",\
"SC_F8",\
"SC_F9",\
"SC_F10",\
"SC_F11",\
"SC_F12"
static int s_pButtonCodeToVirtual[BUTTON_CODE_LAST];
static const char *s_pButtonCodeName[ ] =
{
"", // KEY_NONE
"0", // KEY_0,
"1", // KEY_1,
"2", // KEY_2,
"3", // KEY_3,
"4", // KEY_4,
"5", // KEY_5,
"6", // KEY_6,
"7", // KEY_7,
"8", // KEY_8,
"9", // KEY_9,
"a", // KEY_A,
"b", // KEY_B,
"c", // KEY_C,
"d", // KEY_D,
"e", // KEY_E,
"f", // KEY_F,
"g", // KEY_G,
"h", // KEY_H,
"i", // KEY_I,
"j", // KEY_J,
"k", // KEY_K,
"l", // KEY_L,
"m", // KEY_M,
"n", // KEY_N,
"o", // KEY_O,
"p", // KEY_P,
"q", // KEY_Q,
"r", // KEY_R,
"s", // KEY_S,
"t", // KEY_T,
"u", // KEY_U,
"v", // KEY_V,
"w", // KEY_W,
"x", // KEY_X,
"y", // KEY_Y,
"z", // KEY_Z,
"KP_INS", // KEY_PAD_0,
"KP_END", // KEY_PAD_1,
"KP_DOWNARROW", // KEY_PAD_2,
"KP_PGDN", // KEY_PAD_3,
"KP_LEFTARROW", // KEY_PAD_4,
"KP_5", // KEY_PAD_5,
"KP_RIGHTARROW",// KEY_PAD_6,
"KP_HOME", // KEY_PAD_7,
"KP_UPARROW", // KEY_PAD_8,
"KP_PGUP", // KEY_PAD_9,
"KP_SLASH", // KEY_PAD_DIVIDE,
"KP_MULTIPLY", // KEY_PAD_MULTIPLY,
"KP_MINUS", // KEY_PAD_MINUS,
"KP_PLUS", // KEY_PAD_PLUS,
"KP_ENTER", // KEY_PAD_ENTER,
"KP_DEL", // KEY_PAD_DECIMAL,
"[", // KEY_LBRACKET,
"]", // KEY_RBRACKET,
"SEMICOLON", // KEY_SEMICOLON,
"'", // KEY_APOSTROPHE,
"`", // KEY_BACKQUOTE,
",", // KEY_COMMA,
".", // KEY_PERIOD,
"/", // KEY_SLASH,
"\\", // KEY_BACKSLASH,
"-", // KEY_MINUS,
"=", // KEY_EQUAL,
"ENTER", // KEY_ENTER,
"SPACE", // KEY_SPACE,
"BACKSPACE", // KEY_BACKSPACE,
"TAB", // KEY_TAB,
"CAPSLOCK", // KEY_CAPSLOCK,
"NUMLOCK", // KEY_NUMLOCK,
"ESCAPE", // KEY_ESCAPE,
"SCROLLLOCK", // KEY_SCROLLLOCK,
"INS", // KEY_INSERT,
"DEL", // KEY_DELETE,
"HOME", // KEY_HOME,
"END", // KEY_END,
"PGUP", // KEY_PAGEUP,
"PGDN", // KEY_PAGEDOWN,
"PAUSE", // KEY_BREAK,
"SHIFT", // KEY_LSHIFT,
"RSHIFT", // KEY_RSHIFT,
"ALT", // KEY_LALT,
"RALT", // KEY_RALT,
"CTRL", // KEY_LCONTROL,
"RCTRL", // KEY_RCONTROL,
"LWIN", // KEY_LWIN,
"RWIN", // KEY_RWIN,
"APP", // KEY_APP,
"UPARROW", // KEY_UP,
"LEFTARROW", // KEY_LEFT,
"DOWNARROW", // KEY_DOWN,
"RIGHTARROW", // KEY_RIGHT,
"F1", // KEY_F1,
"F2", // KEY_F2,
"F3", // KEY_F3,
"F4", // KEY_F4,
"F5", // KEY_F5,
"F6", // KEY_F6,
"F7", // KEY_F7,
"F8", // KEY_F8,
"F9", // KEY_F9,
"F10", // KEY_F10,
"F11", // KEY_F11,
"F12", // KEY_F12,
// FIXME: CAPSLOCK/NUMLOCK/SCROLLLOCK all appear above. What are these for?!
// They only appear in CInputWin32::UpdateToggleButtonState in vgui2
"CAPSLOCKTOGGLE", // KEY_CAPSLOCKTOGGLE,
"NUMLOCKTOGGLE", // KEY_NUMLOCKTOGGLE,
"SCROLLLOCKTOGGLE", // KEY_SCROLLLOCKTOGGLE,
// Mouse
"MOUSE1", // MOUSE_LEFT,
"MOUSE2", // MOUSE_RIGHT,
"MOUSE3", // MOUSE_MIDDLE,
"MOUSE4", // MOUSE_4,
"MOUSE5", // MOUSE_5,
"MWHEELUP", // MOUSE_WHEEL_UP
"MWHEELDOWN", // MOUSE_WHEEL_DOWN
#if defined ( _X360 ) || defined ( _LINUX )
"A_BUTTON", // JOYSTICK_FIRST_BUTTON
"B_BUTTON",
"X_BUTTON",
"Y_BUTTON",
"L_SHOULDER",
"R_SHOULDER",
"BACK",
"START",
"STICK1",
"STICK2",
#else
"JOY1", // JOYSTICK_FIRST_BUTTON
"JOY2",
"JOY3",
"JOY4",
"JOY5",
"JOY6",
"JOY7",
"JOY8",
"JOY9",
"JOY10",
#endif
"JOY11",
"JOY12",
"JOY13",
"JOY14",
"JOY15",
"JOY16",
"JOY17",
"JOY18",
"JOY19",
"JOY20",
"JOY21",
"JOY22",
"JOY23",
"JOY24",
"JOY25",
"JOY26",
"JOY27",
"JOY28",
"JOY29",
"JOY30",
"JOY31",
"JOY32", // JOYSTICK_LAST_BUTTON
#if defined ( _X360 )
"UP", // JOYSTICK_FIRST_POV_BUTTON
"RIGHT",
"DOWN",
"LEFT", // JOYSTICK_LAST_POV_BUTTON
"S1_RIGHT", // JOYSTICK_FIRST_AXIS_BUTTON
"S1_LEFT",
"S1_DOWN",
"S1_UP",
"L_TRIGGER",
"R_TRIGGER",
"S2_RIGHT",
"S2_LEFT",
"S2_DOWN",
"S2_UP", // JOYSTICK_LAST_AXIS_BUTTON
"V AXIS POS",
"V AXIS NEG",
#else
"POV_UP", // JOYSTICK_FIRST_POV_BUTTON
"POV_RIGHT",
"POV_DOWN",
"POV_LEFT", // JOYSTICK_LAST_POV_BUTTON
"X AXIS POS", // JOYSTICK_FIRST_AXIS_BUTTON
"X AXIS NEG",
"Y AXIS POS",
"Y AXIS NEG",
"Z AXIS POS",
"Z AXIS NEG",
"R AXIS POS",
"R AXIS NEG",
"U AXIS POS",
"U AXIS NEG",
"V AXIS POS",
"V AXIS NEG", // JOYSTICK_LAST_AXIS_BUTTON
"FALCON_NULL", // NVNT temp Fix for unaligned joystick enumeration
"FALCON_1", // NOVINT_FIRST
"FALCON_2",
"FALCON_3",
"FALCON_4",
"FALCON2_1",
"FALCON2_2",
"FALCON2_3",
"FALCON2_4", // NOVINT_LAST
#endif
SCONTROLLERBUTTONS_BUTTONS( 0 ),
SCONTROLLERBUTTONS_BUTTONS( 1 ),
SCONTROLLERBUTTONS_BUTTONS( 2 ),
SCONTROLLERBUTTONS_BUTTONS( 3 ),
SCONTROLLERBUTTONS_BUTTONS( 4 ),
SCONTROLLERBUTTONS_BUTTONS( 5 ),
SCONTROLLERBUTTONS_BUTTONS( 6 ),
SCONTROLLERBUTTONS_BUTTONS( 7 ),
SCONTROLLERBUTTONS_AXIS( 0 ),
SCONTROLLERBUTTONS_AXIS( 1 ),
SCONTROLLERBUTTONS_AXIS( 2 ),
SCONTROLLERBUTTONS_AXIS( 3 ),
SCONTROLLERBUTTONS_AXIS( 4 ),
SCONTROLLERBUTTONS_AXIS( 5 ),
SCONTROLLERBUTTONS_AXIS( 6 ),
SCONTROLLERBUTTONS_AXIS( 7 ),
SCONTROLLERBUTTONS_VBUTTONS( 0 ),
SCONTROLLERBUTTONS_VBUTTONS( 1 ),
SCONTROLLERBUTTONS_VBUTTONS( 2 ),
SCONTROLLERBUTTONS_VBUTTONS( 3 ),
SCONTROLLERBUTTONS_VBUTTONS( 4 ),
SCONTROLLERBUTTONS_VBUTTONS( 5 ),
SCONTROLLERBUTTONS_VBUTTONS( 6 ),
SCONTROLLERBUTTONS_VBUTTONS( 7 ),
};
static const char *s_pAnalogCodeName[ ] =
{
"MOUSE_X", // MOUSE_X = 0,
"MOUSE_Y", // MOUSE_Y,
"MOUSE_XY", // MOUSE_XY, // Invoked when either x or y changes
"MOUSE_WHEEL", // MOUSE_WHEEL,
"X AXIS", // JOY_AXIS_X
"Y AXIS", // JOY_AXIS_Y
"Z AXIS", // JOY_AXIS_Z
"R AXIS", // JOY_AXIS_R
"U AXIS", // JOY_AXIS_U
"V AXIS", // JOY_AXIS_V
};
#if !defined ( _X360 )
static const char *s_pXControllerButtonCodeNames[ ] =
{
"A_BUTTON", // JOYSTICK_FIRST_BUTTON
"B_BUTTON",
"X_BUTTON",
"Y_BUTTON",
"L_SHOULDER",
"R_SHOULDER",
"BACK",
"START",
"STICK1",
"STICK2",
"JOY11",
"JOY12",
"JOY13",
"JOY14",
"JOY15",
"JOY16",
"JOY17",
"JOY18",
"JOY19",
"JOY20",
"JOY21",
"JOY22",
"JOY23",
"JOY24",
"JOY25",
"JOY26",
"JOY27",
"JOY28",
"JOY29",
"JOY30",
"JOY31",
"JOY32", // JOYSTICK_LAST_BUTTON
"UP", // JOYSTICK_FIRST_POV_BUTTON
"RIGHT",
"DOWN",
"LEFT", // JOYSTICK_LAST_POV_BUTTON
"S1_RIGHT", // JOYSTICK_FIRST_AXIS_BUTTON
"S1_LEFT",
"S1_DOWN",
"S1_UP",
"L_TRIGGER",
"R_TRIGGER",
"S2_RIGHT",
"S2_LEFT",
"S2_DOWN",
"S2_UP", // JOYSTICK_LAST_AXIS_BUTTON
"V AXIS POS",
"V AXIS NEG",
};
#endif
// this maps non-translated keyboard scan codes to engine key codes
// Google for 'Keyboard Scan Code Specification'
static ButtonCode_t s_pScanToButtonCode_QWERTY[128] =
{
// 0 1 2 3 4 5 6 7
// 8 9 A B C D E F
KEY_NONE, KEY_ESCAPE, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, // 0
KEY_7, KEY_8, KEY_9, KEY_0, KEY_MINUS, KEY_EQUAL, KEY_BACKSPACE, KEY_TAB, // 0
KEY_Q, KEY_W, KEY_E, KEY_R, KEY_T, KEY_Y, KEY_U, KEY_I, // 1
KEY_O, KEY_P, KEY_LBRACKET, KEY_RBRACKET, KEY_ENTER, KEY_LCONTROL, KEY_A, KEY_S, // 1
KEY_D, KEY_F, KEY_G, KEY_H, KEY_J, KEY_K, KEY_L, KEY_SEMICOLON, // 2
KEY_APOSTROPHE, KEY_BACKQUOTE, KEY_LSHIFT, KEY_BACKSLASH, KEY_Z, KEY_X, KEY_C, KEY_V, // 2
KEY_B, KEY_N, KEY_M, KEY_COMMA, KEY_PERIOD, KEY_SLASH, KEY_RSHIFT, KEY_PAD_MULTIPLY,// 3
KEY_LALT, KEY_SPACE, KEY_CAPSLOCK, KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, // 3
KEY_F6, KEY_F7, KEY_F8, KEY_F9, KEY_F10, KEY_NUMLOCK, KEY_SCROLLLOCK, KEY_HOME, // 4
KEY_UP, KEY_PAGEUP, KEY_PAD_MINUS, KEY_LEFT, KEY_PAD_5, KEY_RIGHT, KEY_PAD_PLUS, KEY_END, // 4
KEY_DOWN, KEY_PAGEDOWN, KEY_INSERT, KEY_DELETE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_F11, // 5
KEY_F12, KEY_BREAK, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, // 5
KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, // 6
KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, // 6
KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, // 7
KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE // 7
};
static ButtonCode_t s_pScanToButtonCode[128];
void ButtonCode_InitKeyTranslationTable()
{
COMPILE_TIME_ASSERT( sizeof(s_pButtonCodeName) / sizeof( const char * ) == BUTTON_CODE_LAST );
COMPILE_TIME_ASSERT( sizeof(s_pAnalogCodeName) / sizeof( const char * ) == ANALOG_CODE_LAST );
// set virtual key translation table
memset( s_pVirtualKeyToButtonCode, KEY_NONE, sizeof(s_pVirtualKeyToButtonCode) );
s_pVirtualKeyToButtonCode['0'] =KEY_0;
s_pVirtualKeyToButtonCode['1'] =KEY_1;
s_pVirtualKeyToButtonCode['2'] =KEY_2;
s_pVirtualKeyToButtonCode['3'] =KEY_3;
s_pVirtualKeyToButtonCode['4'] =KEY_4;
s_pVirtualKeyToButtonCode['5'] =KEY_5;
s_pVirtualKeyToButtonCode['6'] =KEY_6;
s_pVirtualKeyToButtonCode['7'] =KEY_7;
s_pVirtualKeyToButtonCode['8'] =KEY_8;
s_pVirtualKeyToButtonCode['9'] =KEY_9;
s_pVirtualKeyToButtonCode['A'] =KEY_A;
s_pVirtualKeyToButtonCode['B'] =KEY_B;
s_pVirtualKeyToButtonCode['C'] =KEY_C;
s_pVirtualKeyToButtonCode['D'] =KEY_D;
s_pVirtualKeyToButtonCode['E'] =KEY_E;
s_pVirtualKeyToButtonCode['F'] =KEY_F;
s_pVirtualKeyToButtonCode['G'] =KEY_G;
s_pVirtualKeyToButtonCode['H'] =KEY_H;
s_pVirtualKeyToButtonCode['I'] =KEY_I;
s_pVirtualKeyToButtonCode['J'] =KEY_J;
s_pVirtualKeyToButtonCode['K'] =KEY_K;
s_pVirtualKeyToButtonCode['L'] =KEY_L;
s_pVirtualKeyToButtonCode['M'] =KEY_M;
s_pVirtualKeyToButtonCode['N'] =KEY_N;
s_pVirtualKeyToButtonCode['O'] =KEY_O;
s_pVirtualKeyToButtonCode['P'] =KEY_P;
s_pVirtualKeyToButtonCode['Q'] =KEY_Q;
s_pVirtualKeyToButtonCode['R'] =KEY_R;
s_pVirtualKeyToButtonCode['S'] =KEY_S;
s_pVirtualKeyToButtonCode['T'] =KEY_T;
s_pVirtualKeyToButtonCode['U'] =KEY_U;
s_pVirtualKeyToButtonCode['V'] =KEY_V;
s_pVirtualKeyToButtonCode['W'] =KEY_W;
s_pVirtualKeyToButtonCode['X'] =KEY_X;
s_pVirtualKeyToButtonCode['Y'] =KEY_Y;
s_pVirtualKeyToButtonCode['Z'] =KEY_Z;
#if !defined( POSIX )
s_pVirtualKeyToButtonCode[VK_NUMPAD0] =KEY_PAD_0;
s_pVirtualKeyToButtonCode[VK_NUMPAD1] =KEY_PAD_1;
s_pVirtualKeyToButtonCode[VK_NUMPAD2] =KEY_PAD_2;
s_pVirtualKeyToButtonCode[VK_NUMPAD3] =KEY_PAD_3;
s_pVirtualKeyToButtonCode[VK_NUMPAD4] =KEY_PAD_4;
s_pVirtualKeyToButtonCode[VK_NUMPAD5] =KEY_PAD_5;
s_pVirtualKeyToButtonCode[VK_NUMPAD6] =KEY_PAD_6;
s_pVirtualKeyToButtonCode[VK_NUMPAD7] =KEY_PAD_7;
s_pVirtualKeyToButtonCode[VK_NUMPAD8] =KEY_PAD_8;
s_pVirtualKeyToButtonCode[VK_NUMPAD9] =KEY_PAD_9;
s_pVirtualKeyToButtonCode[VK_DIVIDE] =KEY_PAD_DIVIDE;
s_pVirtualKeyToButtonCode[VK_MULTIPLY] =KEY_PAD_MULTIPLY;
s_pVirtualKeyToButtonCode[VK_SUBTRACT] =KEY_PAD_MINUS;
s_pVirtualKeyToButtonCode[VK_ADD] =KEY_PAD_PLUS;
s_pVirtualKeyToButtonCode[VK_RETURN] =KEY_PAD_ENTER;
s_pVirtualKeyToButtonCode[VK_DECIMAL] =KEY_PAD_DECIMAL;
#endif
s_pVirtualKeyToButtonCode[0xdb] =KEY_LBRACKET;
s_pVirtualKeyToButtonCode[0xdd] =KEY_RBRACKET;
s_pVirtualKeyToButtonCode[0xba] =KEY_SEMICOLON;
s_pVirtualKeyToButtonCode[0xde] =KEY_APOSTROPHE;
s_pVirtualKeyToButtonCode[0xc0] =KEY_BACKQUOTE;
s_pVirtualKeyToButtonCode[0xbc] =KEY_COMMA;
s_pVirtualKeyToButtonCode[0xbe] =KEY_PERIOD;
s_pVirtualKeyToButtonCode[0xbf] =KEY_SLASH;
s_pVirtualKeyToButtonCode[0xdc] =KEY_BACKSLASH;
s_pVirtualKeyToButtonCode[0xbd] =KEY_MINUS;
s_pVirtualKeyToButtonCode[0xbb] =KEY_EQUAL;
#if !defined( POSIX )
s_pVirtualKeyToButtonCode[VK_RETURN] =KEY_ENTER;
s_pVirtualKeyToButtonCode[VK_SPACE] =KEY_SPACE;
s_pVirtualKeyToButtonCode[VK_BACK] =KEY_BACKSPACE;
s_pVirtualKeyToButtonCode[VK_TAB] =KEY_TAB;
s_pVirtualKeyToButtonCode[VK_CAPITAL] =KEY_CAPSLOCK;
s_pVirtualKeyToButtonCode[VK_NUMLOCK] =KEY_NUMLOCK;
s_pVirtualKeyToButtonCode[VK_ESCAPE] =KEY_ESCAPE;
s_pVirtualKeyToButtonCode[VK_SCROLL] =KEY_SCROLLLOCK;
s_pVirtualKeyToButtonCode[VK_INSERT] =KEY_INSERT;
s_pVirtualKeyToButtonCode[VK_DELETE] =KEY_DELETE;
s_pVirtualKeyToButtonCode[VK_HOME] =KEY_HOME;
s_pVirtualKeyToButtonCode[VK_END] =KEY_END;
s_pVirtualKeyToButtonCode[VK_PRIOR] =KEY_PAGEUP;
s_pVirtualKeyToButtonCode[VK_NEXT] =KEY_PAGEDOWN;
s_pVirtualKeyToButtonCode[VK_PAUSE] =KEY_BREAK;
s_pVirtualKeyToButtonCode[VK_SHIFT] =KEY_RSHIFT;
s_pVirtualKeyToButtonCode[VK_SHIFT] =KEY_LSHIFT; // SHIFT -> left SHIFT
s_pVirtualKeyToButtonCode[VK_MENU] =KEY_RALT;
s_pVirtualKeyToButtonCode[VK_MENU] =KEY_LALT; // ALT -> left ALT
s_pVirtualKeyToButtonCode[VK_CONTROL] =KEY_RCONTROL;
s_pVirtualKeyToButtonCode[VK_CONTROL] =KEY_LCONTROL; // CTRL -> left CTRL
s_pVirtualKeyToButtonCode[VK_LWIN] =KEY_LWIN;
s_pVirtualKeyToButtonCode[VK_RWIN] =KEY_RWIN;
s_pVirtualKeyToButtonCode[VK_APPS] =KEY_APP;
s_pVirtualKeyToButtonCode[VK_UP] =KEY_UP;
s_pVirtualKeyToButtonCode[VK_LEFT] =KEY_LEFT;
s_pVirtualKeyToButtonCode[VK_DOWN] =KEY_DOWN;
s_pVirtualKeyToButtonCode[VK_RIGHT] =KEY_RIGHT;
s_pVirtualKeyToButtonCode[VK_F1] =KEY_F1;
s_pVirtualKeyToButtonCode[VK_F2] =KEY_F2;
s_pVirtualKeyToButtonCode[VK_F3] =KEY_F3;
s_pVirtualKeyToButtonCode[VK_F4] =KEY_F4;
s_pVirtualKeyToButtonCode[VK_F5] =KEY_F5;
s_pVirtualKeyToButtonCode[VK_F6] =KEY_F6;
s_pVirtualKeyToButtonCode[VK_F7] =KEY_F7;
s_pVirtualKeyToButtonCode[VK_F8] =KEY_F8;
s_pVirtualKeyToButtonCode[VK_F9] =KEY_F9;
s_pVirtualKeyToButtonCode[VK_F10] =KEY_F10;
s_pVirtualKeyToButtonCode[VK_F11] =KEY_F11;
s_pVirtualKeyToButtonCode[VK_F12] =KEY_F12;
#endif
// init the xkey translation table
#if !defined( POSIX )
s_pXKeyTrans[XK_NULL] = KEY_NONE;
s_pXKeyTrans[XK_BUTTON_UP] = KEY_XBUTTON_UP;
s_pXKeyTrans[XK_BUTTON_DOWN] = KEY_XBUTTON_DOWN;
s_pXKeyTrans[XK_BUTTON_LEFT] = KEY_XBUTTON_LEFT;
s_pXKeyTrans[XK_BUTTON_RIGHT] = KEY_XBUTTON_RIGHT;
s_pXKeyTrans[XK_BUTTON_START] = KEY_XBUTTON_START;
s_pXKeyTrans[XK_BUTTON_BACK] = KEY_XBUTTON_BACK;
s_pXKeyTrans[XK_BUTTON_STICK1] = KEY_XBUTTON_STICK1;
s_pXKeyTrans[XK_BUTTON_STICK2] = KEY_XBUTTON_STICK2;
s_pXKeyTrans[XK_BUTTON_A] = KEY_XBUTTON_A;
s_pXKeyTrans[XK_BUTTON_B] = KEY_XBUTTON_B;
s_pXKeyTrans[XK_BUTTON_X] = KEY_XBUTTON_X;
s_pXKeyTrans[XK_BUTTON_Y] = KEY_XBUTTON_Y;
s_pXKeyTrans[XK_BUTTON_LEFT_SHOULDER] = KEY_XBUTTON_LEFT_SHOULDER;
s_pXKeyTrans[XK_BUTTON_RIGHT_SHOULDER] = KEY_XBUTTON_RIGHT_SHOULDER;
s_pXKeyTrans[XK_BUTTON_LTRIGGER] = KEY_XBUTTON_LTRIGGER;
s_pXKeyTrans[XK_BUTTON_RTRIGGER] = KEY_XBUTTON_RTRIGGER;
s_pXKeyTrans[XK_STICK1_UP] = KEY_XSTICK1_UP;
s_pXKeyTrans[XK_STICK1_DOWN] = KEY_XSTICK1_DOWN;
s_pXKeyTrans[XK_STICK1_LEFT] = KEY_XSTICK1_LEFT;
s_pXKeyTrans[XK_STICK1_RIGHT] = KEY_XSTICK1_RIGHT;
s_pXKeyTrans[XK_STICK2_UP] = KEY_XSTICK2_UP;
s_pXKeyTrans[XK_STICK2_DOWN] = KEY_XSTICK2_DOWN;
s_pXKeyTrans[XK_STICK2_LEFT] = KEY_XSTICK2_LEFT;
s_pXKeyTrans[XK_STICK2_RIGHT] = KEY_XSTICK2_RIGHT;
#endif // PLATFORM_POSIX
// create reverse table engine to virtual
for ( int i = 0; i < ARRAYSIZE( s_pVirtualKeyToButtonCode ); i++ )
{
s_pButtonCodeToVirtual[ s_pVirtualKeyToButtonCode[i] ] = i;
}
s_pButtonCodeToVirtual[0] = 0;
s_pSKeytoButtonCode[SK_NULL] = KEY_NONE;
s_pSKeytoButtonCode[SK_BUTTON_A] = STEAMCONTROLLER_A;
s_pSKeytoButtonCode[SK_BUTTON_B] = STEAMCONTROLLER_B;
s_pSKeytoButtonCode[SK_BUTTON_X] = STEAMCONTROLLER_X;
s_pSKeytoButtonCode[SK_BUTTON_Y] = STEAMCONTROLLER_Y;
s_pSKeytoButtonCode[SK_BUTTON_UP] = STEAMCONTROLLER_DPAD_UP;
s_pSKeytoButtonCode[SK_BUTTON_RIGHT] = STEAMCONTROLLER_DPAD_RIGHT;
s_pSKeytoButtonCode[SK_BUTTON_DOWN] = STEAMCONTROLLER_DPAD_DOWN;
s_pSKeytoButtonCode[SK_BUTTON_LEFT] = STEAMCONTROLLER_DPAD_LEFT;
s_pSKeytoButtonCode[SK_BUTTON_LEFT_BUMPER] = STEAMCONTROLLER_LEFT_BUMPER;
s_pSKeytoButtonCode[SK_BUTTON_RIGHT_BUMPER] = STEAMCONTROLLER_RIGHT_BUMPER;
s_pSKeytoButtonCode[SK_BUTTON_LEFT_TRIGGER] = STEAMCONTROLLER_LEFT_TRIGGER;
s_pSKeytoButtonCode[SK_BUTTON_RIGHT_TRIGGER] = STEAMCONTROLLER_RIGHT_TRIGGER;
s_pSKeytoButtonCode[SK_BUTTON_LEFT_GRIP] = STEAMCONTROLLER_LEFT_GRIP;
s_pSKeytoButtonCode[SK_BUTTON_RIGHT_GRIP] = STEAMCONTROLLER_RIGHT_GRIP;
s_pSKeytoButtonCode[SK_BUTTON_LPAD_TOUCH] = STEAMCONTROLLER_LEFT_PAD_FINGERDOWN;
s_pSKeytoButtonCode[SK_BUTTON_RPAD_TOUCH] = STEAMCONTROLLER_RIGHT_PAD_FINGERDOWN;
s_pSKeytoButtonCode[SK_BUTTON_LPAD_CLICK] = STEAMCONTROLLER_LEFT_PAD_CLICK;
s_pSKeytoButtonCode[SK_BUTTON_RPAD_CLICK] = STEAMCONTROLLER_RIGHT_PAD_CLICK;
s_pSKeytoButtonCode[SK_BUTTON_LPAD_UP] = STEAMCONTROLLER_LEFT_PAD_UP;
s_pSKeytoButtonCode[SK_BUTTON_LPAD_RIGHT] = STEAMCONTROLLER_LEFT_PAD_RIGHT;
s_pSKeytoButtonCode[SK_BUTTON_LPAD_DOWN] = STEAMCONTROLLER_LEFT_PAD_DOWN;
s_pSKeytoButtonCode[SK_BUTTON_LPAD_LEFT] = STEAMCONTROLLER_LEFT_PAD_LEFT;
s_pSKeytoButtonCode[SK_BUTTON_RPAD_UP] = STEAMCONTROLLER_RIGHT_PAD_UP;
s_pSKeytoButtonCode[SK_BUTTON_RPAD_RIGHT] = STEAMCONTROLLER_RIGHT_PAD_RIGHT;
s_pSKeytoButtonCode[SK_BUTTON_RPAD_DOWN] = STEAMCONTROLLER_RIGHT_PAD_DOWN;
s_pSKeytoButtonCode[SK_BUTTON_RPAD_LEFT] = STEAMCONTROLLER_RIGHT_PAD_LEFT;
s_pSKeytoButtonCode[SK_BUTTON_SELECT] = STEAMCONTROLLER_SELECT;
s_pSKeytoButtonCode[SK_BUTTON_START] = STEAMCONTROLLER_START;
s_pSKeytoButtonCode[SK_BUTTON_STEAM] = STEAMCONTROLLER_STEAM;
s_pSKeytoButtonCode[SK_BUTTON_INACTIVE_START] = STEAMCONTROLLER_INACTIVE_START;
// These are fake ("virtual") steam controller buttons that don't physically exist, but we can manufacture to make internal routing
// to old school UI (which is expecting button code rather than actions) without clashing with other butt
s_pSKeytoButtonCode[SK_VBUTTON_F1] = STEAMCONTROLLER_F1;
s_pSKeytoButtonCode[SK_VBUTTON_F2] = STEAMCONTROLLER_F2;
s_pSKeytoButtonCode[SK_VBUTTON_F3] = STEAMCONTROLLER_F3;
s_pSKeytoButtonCode[SK_VBUTTON_F4] = STEAMCONTROLLER_F4;
s_pSKeytoButtonCode[SK_VBUTTON_F5] = STEAMCONTROLLER_F5;
s_pSKeytoButtonCode[SK_VBUTTON_F6] = STEAMCONTROLLER_F6;
s_pSKeytoButtonCode[SK_VBUTTON_F7] = STEAMCONTROLLER_F7;
s_pSKeytoButtonCode[SK_VBUTTON_F8] = STEAMCONTROLLER_F8;
s_pSKeytoButtonCode[SK_VBUTTON_F9] = STEAMCONTROLLER_F9;
s_pSKeytoButtonCode[SK_VBUTTON_F10] = STEAMCONTROLLER_F10;
s_pSKeytoButtonCode[SK_VBUTTON_F11] = STEAMCONTROLLER_F11;
s_pSKeytoButtonCode[SK_VBUTTON_F12] = STEAMCONTROLLER_F12;
}
ButtonCode_t ButtonCode_VirtualKeyToButtonCode( int keyCode )
{
if ( keyCode < 0 || keyCode >= sizeof( s_pVirtualKeyToButtonCode ) / sizeof( s_pVirtualKeyToButtonCode[0] ) )
{
Assert( false );
return KEY_NONE;
}
return s_pVirtualKeyToButtonCode[keyCode];
}
int ButtonCode_ButtonCodeToVirtualKey( ButtonCode_t code )
{
return s_pButtonCodeToVirtual[code];
}
ButtonCode_t ButtonCode_XKeyToButtonCode( int nPort, int keyCode )
{
#if !defined( POSIX )
if ( keyCode < 0 || keyCode >= sizeof( s_pXKeyTrans ) / sizeof( s_pXKeyTrans[0] ) )
{
Assert( false );
return KEY_NONE;
}
ButtonCode_t code = s_pXKeyTrans[keyCode];
if ( IsJoystickButtonCode( code ) )
{
int nOffset = code - JOYSTICK_FIRST_BUTTON;
return JOYSTICK_BUTTON( nPort, nOffset );
}
if ( IsJoystickPOVCode( code ) )
{
int nOffset = code - JOYSTICK_FIRST_POV_BUTTON;
return JOYSTICK_POV_BUTTON( nPort, nOffset );
}
if ( IsJoystickAxisCode( code ) )
{
int nOffset = code - JOYSTICK_FIRST_AXIS_BUTTON;
return JOYSTICK_AXIS_BUTTON( nPort, nOffset );
}
return code;
#else // POSIX
return KEY_NONE;
#endif // POSIX
}
// Convert back + forth between ButtonCode/AnalogCode + strings
const char *ButtonCode_ButtonCodeToString( ButtonCode_t code, bool bXController )
{
#if !defined ( _X360 )
if ( bXController && code >= JOYSTICK_FIRST_BUTTON && code <= JOYSTICK_LAST_AXIS_BUTTON )
return s_pXControllerButtonCodeNames[ code - JOYSTICK_FIRST_BUTTON ];
#endif
return s_pButtonCodeName[ code ];
}
const char *AnalogCode_AnalogCodeToString( AnalogCode_t code )
{
return s_pAnalogCodeName[ code ];
}
ButtonCode_t ButtonCode_StringToButtonCode( const char *pString, bool bXController )
{
if ( !pString || !pString[0] )
return BUTTON_CODE_INVALID;
// Backward compat for screwed up previous joystick button names
if ( !Q_strnicmp( pString, "aux", 3 ) )
{
int nIndex = atoi( &pString[3] );
if ( nIndex < 29 )
return JOYSTICK_BUTTON( 0, nIndex );
if ( ( nIndex >= 29 ) && ( nIndex <= 32 ) )
return JOYSTICK_POV_BUTTON( 0, nIndex - 29 );
return BUTTON_CODE_INVALID;
}
for ( int i = 0; i < BUTTON_CODE_LAST; ++i )
{
if ( !Q_stricmp( s_pButtonCodeName[i], pString ) )
return (ButtonCode_t)i;
}
#if !defined ( _X360 )
if ( bXController )
{
for ( int i = 0; i < ARRAYSIZE(s_pXControllerButtonCodeNames); ++i )
{
if ( !Q_stricmp( s_pXControllerButtonCodeNames[i], pString ) )
return (ButtonCode_t)(JOYSTICK_FIRST_BUTTON + i);
}
}
#endif
return BUTTON_CODE_INVALID;
}
ButtonCode_t ButtonCode_SKeyToButtonCode( int nPort, int keyCode )
{
#if !defined( _GAMECONSOLE )
if ( keyCode < 0 || keyCode >= sizeof( s_pSKeytoButtonCode ) / sizeof( s_pSKeytoButtonCode[0] ) )
{
Assert( false );
return KEY_NONE;
}
ButtonCode_t code = s_pSKeytoButtonCode[keyCode];
// if ( IsSteamControllerCode( code ) )
// {
// // Need Per Controller Offset here.
// return code;
// }
if ( IsSteamControllerButtonCode( code ) )
{
int nOffset = code - STEAMCONTROLLER_FIRST_BUTTON;
return STEAMCONTROLLER_BUTTON( nPort, nOffset );
}
if ( IsSteamControllerAxisCode( code ) )
{
int nOffset = code - STEAMCONTROLLER_FIRST_AXIS_BUTTON;
return STEAMCONTROLLER_AXIS_BUTTON( nPort, nOffset );
}
return code;
#else // _GAMECONSOLE
return KEY_NONE;
#endif // _GAMECONSOLE
}
AnalogCode_t AnalogCode_StringToAnalogCode( const char *pString )
{
if ( !pString || !pString[0] )
return ANALOG_CODE_INVALID;
for ( int i = 0; i < ANALOG_CODE_LAST; ++i )
{
if ( !Q_stricmp( s_pAnalogCodeName[i], pString ) )
return (AnalogCode_t)i;
}
return ANALOG_CODE_INVALID;
}
ButtonCode_t ButtonCode_ScanCodeToButtonCode( int lParam )
{
int nScanCode = ( lParam >> 16 ) & 0xFF;
if ( nScanCode > 127 )
return KEY_NONE;
ButtonCode_t result = s_pScanToButtonCode[nScanCode];
bool bIsExtended = ( lParam & ( 1 << 24 ) ) != 0;
if ( !bIsExtended )
{
switch ( result )
{
case KEY_HOME:
return KEY_PAD_7;
case KEY_UP:
return KEY_PAD_8;
case KEY_PAGEUP:
return KEY_PAD_9;
case KEY_LEFT:
return KEY_PAD_4;
case KEY_RIGHT:
return KEY_PAD_6;
case KEY_END:
return KEY_PAD_1;
case KEY_DOWN:
return KEY_PAD_2;
case KEY_PAGEDOWN:
return KEY_PAD_3;
case KEY_INSERT:
return KEY_PAD_0;
case KEY_DELETE:
return KEY_PAD_DECIMAL;
default:
break;
}
}
else
{
switch ( result )
{
case KEY_ENTER:
return KEY_PAD_ENTER;
case KEY_LALT:
return KEY_RALT;
case KEY_LCONTROL:
return KEY_RCONTROL;
case KEY_SLASH:
return KEY_PAD_DIVIDE;
case KEY_CAPSLOCK:
return KEY_PAD_PLUS;
}
}
return result;
}
//-----------------------------------------------------------------------------
// Update scan codes for foreign keyboards
//-----------------------------------------------------------------------------
void ButtonCode_UpdateScanCodeLayout( )
{
// reset the keyboard
memcpy( s_pScanToButtonCode, s_pScanToButtonCode_QWERTY, sizeof(s_pScanToButtonCode) );
#if !defined( _X360 ) && !defined( POSIX )
// fix up keyboard layout for other languages
HKL currentKb = ::GetKeyboardLayout( 0 );
HKL englishKb = ::LoadKeyboardLayout("00000409", 0);
if (englishKb && englishKb != currentKb)
{
for ( int i = 0; i < ARRAYSIZE(s_pScanToButtonCode); i++ )
{
// take the english/QWERTY
ButtonCode_t code = s_pScanToButtonCode_QWERTY[ i ];
// only remap printable keys
if ( code != KEY_NONE && code != KEY_BACKQUOTE && ( IsAlphaNumeric( code ) || IsPunctuation( code ) ) )
{
// get it's virtual key based on the old layout
int vk = ::MapVirtualKeyEx( i, 1, englishKb );
// turn in into a scancode on the new layout
int newScanCode = ::MapVirtualKeyEx( vk, 0, currentKb );
// strip off any high bits
newScanCode &= 0x0000007F;
// set in the new layout
s_pScanToButtonCode[newScanCode] = code;
}
}
}
s_pScanToButtonCode[0] = KEY_NONE;
#endif
}
//-----------------------------------------------------------------------------
// Purpose: Updates the current keyboard layout
//-----------------------------------------------------------------------------
CON_COMMAND( key_updatelayout, "Updates game keyboard layout to current windows keyboard setting." )
{
ButtonCode_UpdateScanCodeLayout();
}
+38
View File
@@ -0,0 +1,38 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//===========================================================================//
#ifndef KEY_TRANSLATION_H
#define KEY_TRANSLATION_H
#ifdef _WIN32
#pragma once
#endif
#include "inputsystem/ButtonCode.h"
#include "inputsystem/AnalogCode.h"
// Call this to initialize the system
void ButtonCode_InitKeyTranslationTable();
// Convert from Windows scan codes to Button codes.
ButtonCode_t ButtonCode_ScanCodeToButtonCode( int lParam );
// Update scan codes for foreign keyboards
void ButtonCode_UpdateScanCodeLayout( );
// Convert from Windows virtual key codes to Button codes.
ButtonCode_t ButtonCode_VirtualKeyToButtonCode( int keyCode );
int ButtonCode_ButtonCodeToVirtualKey( ButtonCode_t code );
ButtonCode_t ButtonCode_XKeyToButtonCode( int nPort, int keyCode );
// Convert back + forth between ButtonCode/AnalogCode + strings
const char *ButtonCode_ButtonCodeToString( ButtonCode_t code, bool bXController );
const char *AnalogCode_AnalogCodeToString( AnalogCode_t code );
ButtonCode_t ButtonCode_StringToButtonCode( const char *pString, bool bXController );
AnalogCode_t AnalogCode_StringToAnalogCode( const char *pString );
ButtonCode_t ButtonCode_SKeyToButtonCode( int nPort, int keyCode );
#endif // KEY_TRANSLATION_H
+138
View File
@@ -0,0 +1,138 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//===========================================================================//
#include "inputsystem.h"
#include "key_translation.h"
#include "inputsystem/ButtonCode.h"
#include "inputsystem/AnalogCode.h"
#include "tier1/convar.h"
typedef void*(*NovintGetIHaptics_t)(void);
typedef bool (*NovintAttemptHWND_t)(void *hWnd);
typedef void (*NovintDisableHWND_t)(void);
typedef void (*NovintPollDevices_t)(void);
typedef bool (*NovintButtonState_t)(int nDevice,
int &down,
int &pressed,
int &released);
typedef int (*NovintDeviceCount_t)();
typedef int (*NovintButtonCount_t)(int nDevice);
typedef bool (__cdecl *NovintMouseModeCallback_t) (void);
typedef void (*NovintInputActive_t)(bool bGameInput);
typedef __int64 (*NovintGetDeviceID_t)(int nDevice);
NovintGetIHaptics_t NovintGetIHaptics = NULL;
NovintAttemptHWND_t NovintAttemptHWND = NULL;
NovintDisableHWND_t NovintDisableHWND = NULL;
NovintPollDevices_t NovintPollDevices = NULL;
NovintButtonState_t NovintButtonState = NULL;
NovintDeviceCount_t NovintDeviceCount = NULL;
NovintButtonCount_t NovintButtonCount = NULL;
NovintInputActive_t NovintInputActive = NULL;
NovintGetDeviceID_t NovintGetDeviceID = NULL;
static CInputSystem *pNovintInputSystem = 0;
static bool bNovintPure = false;
bool __cdecl NovintDevicesInputMode(void)
{
if(pNovintInputSystem)
{
return !bNovintPure;
}
return false;
}
void *CInputSystem::GetHapticsInterfaceAddress(void)const
{
if( NovintGetIHaptics )
return NovintGetIHaptics();
return NULL;
}
void CInputSystem::AttachWindowToNovintDevices( void * hWnd )
{
if( NovintAttemptHWND )
NovintAttemptHWND( hWnd );
}
void CInputSystem::DetachWindowFromNovintDevices(void)
{
if( NovintDisableHWND )
NovintDisableHWND();
}
void CInputSystem::InitializeNovintDevices()
{
pNovintInputSystem = this;
// assume no novint devices
m_bNovintDevices = false;
m_nNovintDeviceCount = 0;
if(!m_pNovintDLL)
return;
NovintGetIHaptics = (NovintGetIHaptics_t)GetProcAddress( (HMODULE)m_pNovintDLL, "NovintGetIHaptics" );
NovintAttemptHWND = (NovintAttemptHWND_t)GetProcAddress( (HMODULE)m_pNovintDLL, "NovintAttemptHWND" );
NovintDisableHWND = (NovintDisableHWND_t)GetProcAddress( (HMODULE)m_pNovintDLL, "NovintDisableHWND" );
NovintPollDevices = (NovintPollDevices_t)GetProcAddress( (HMODULE)m_pNovintDLL, "NovintPollDevices" );
NovintButtonState = (NovintButtonState_t)GetProcAddress( (HMODULE)m_pNovintDLL, "NovintButtonState" );
NovintDeviceCount = (NovintDeviceCount_t)GetProcAddress( (HMODULE)m_pNovintDLL, "NovintDeviceCount" );
NovintButtonCount = (NovintButtonCount_t)GetProcAddress( (HMODULE)m_pNovintDLL, "NovintButtonCount" );
NovintGetDeviceID = (NovintGetDeviceID_t)GetProcAddress( (HMODULE)m_pNovintDLL, "NovintGetDeviceID" );
NovintInputActive = (NovintInputActive_t)GetProcAddress( (HMODULE)m_pNovintDLL, "NovintInputActive" );
m_nNovintDeviceCount = NovintDeviceCount();
if( m_nNovintDeviceCount > 0 )
m_bNovintDevices = true;
}
void CInputSystem::PollNovintDevices()
{
if( NovintPollDevices )
NovintPollDevices();
for ( int i = 0; i < m_nNovintDeviceCount; i++ )
{
UpdateNovintDeviceButtonState(i);
}
}
void CInputSystem::UpdateNovintDeviceButtonState(int nDevice)
{
int nDown;
int nPressed;
int nReleased;
if(NovintButtonState(nDevice, nDown, nPressed, nReleased))
{
for ( int i = 0; i < 4; i++ )
{
ButtonCode_t code = (ButtonCode_t)( NOVINT_FIRST + ( nDevice * 4 ) + i );
if( nPressed & (1 << i) )
{
PostButtonPressedEvent(IE_ButtonPressed, m_nLastSampleTick, code, KEY_NONE);
}
if( nReleased & (1 << i) )
{
PostButtonReleasedEvent(IE_ButtonReleased, m_nLastSampleTick, code, KEY_NONE);
}
}
}
}
void CInputSystem::SetNovintPure( bool bPure )
{
bNovintPure = bPure;
if(NovintInputActive)
NovintInputActive(bNovintPure);
}
+75
View File
@@ -0,0 +1,75 @@
//========= Copyright Valve Corporation, All rights reserved. ============//
//
//
//
//==================================================================================================
#ifndef POSIX_WIN32STUBS_H
#define POSIX_WIN32STUBS_H
#ifdef _WIN32
#pragma once
#endif
#include "tier0/basetypes.h"
#include "tier0/platform.h"
typedef int32 LRESULT;
typedef void* HWND;
typedef uint32 UINT;
typedef uintp WPARAM;
typedef uintp LPARAM;
typedef uint8 BYTE;
typedef int16 SHORT;
typedef void* WNDPROC;
typedef void* HANDLE;
typedef char xKey_t;
#define XUSER_MAX_COUNT 2
#define XK_MAX_KEYS 5
typedef struct joyinfoex_tag
{
DWORD dwSize;
DWORD dwFlags;
DWORD dwXpos;
DWORD dwYpos;
DWORD dwZpos;
DWORD dwRpos;
DWORD dwUpos;
DWORD dwVpos;
DWORD dwButtons;
DWORD dwButtonNumber;
DWORD dwPOV;
DWORD dwReserved1;
DWORD dwReserved2;
} JOYINFOEX, *LPJOYINFOEX;
typedef struct _XINPUT_GAMEPAD
{
WORD wButtons;
BYTE bLeftTrigger;
BYTE bRightTrigger;
SHORT sThumbLX;
SHORT sThumbLY;
SHORT sThumbRX;
SHORT sThumbRY;
} XINPUT_GAMEPAD, *PXINPUT_GAMEPAD;
typedef struct _XINPUT_STATE
{
DWORD dwPacketNumber;
XINPUT_GAMEPAD Gamepad;
} XINPUT_STATE, *PXINPUT_STATE;
typedef struct _XINPUT_VIBRATION
{
WORD wLeftMotorSpeed;
WORD wRightMotorSpeed;
} XINPUT_VIBRATION, *PXINPUT_VIBRATION;
#endif // POSIX_WIN32STUBS_H
+695
View File
@@ -0,0 +1,695 @@
//=========== Copyright Valve Corporation, All rights reserved. ===============//
//
// Purpose: Native Steam Controller Interface
//=============================================================================//
#include "inputsystem.h"
#include "key_translation.h"
#include "filesystem.h"
#include "steam/isteamcontroller.h"
#include "math.h"
#ifndef UINT64_MAX
const uint64 UINT64_MAX = 0xffffffffffffffff;
#endif
#if !defined( NO_STEAM )
#include "steam/steam_api.h"
#endif //NO_STEAM
// memdbgon must be the last include file in a .cpp file!!!
#include <tier0/memdbgon.h>
ConVar sc_joystick_map( "sc_joystick_map", "1", FCVAR_ARCHIVE, "How to map the analog joystick deadzone and extents 0 = Scaled Cross, 1 = Concentric Mapping to Square." );
#define STEAMPAD_MAX_ANALOGSAMPLE_GYRO 32768
#define STEAMPAD_MAX_ANALOGSAMPLE_TRIGGER 32768
#define STEAMPAD_MAX_ANALOGSAMPLE_LEFT 32768
#define STEAMPAD_MAX_ANALOGSAMPLE_RIGHT 32767
#define STEAMPAD_MAX_ANALOGSAMPLE_DOWN 32768
#define STEAMPAD_MAX_ANALOGSAMPLE_UP 32767
#define STEAMPAD_MAX_ANALOGSAMPLE_MAX 32768
#define STEAMPAD_ANALOG_SCALE_LEFT(x) ( ( float )STEAMPAD_MAX_ANALOGSAMPLE_LEFT/( float )( STEAMPAD_MAX_ANALOGSAMPLE_LEFT-(x) ) )
#define STEAMPAD_ANALOG_SCALE_RIGHT(x) ( ( float )STEAMPAD_MAX_ANALOGSAMPLE_RIGHT/( float )( STEAMPAD_MAX_ANALOGSAMPLE_RIGHT-(x) ) )
#define STEAMPAD_ANALOG_SCALE_DOWN(x) ( ( float )STEAMPAD_MAX_ANALOGSAMPLE_DOWN/( float )( STEAMPAD_MAX_ANALOGSAMPLE_DOWN-(x) ) )
#define STEAMPAD_ANALOG_SCALE_UP(x) ( ( float )STEAMPAD_MAX_ANALOGSAMPLE_UP/( float )( STEAMPAD_MAX_ANALOGSAMPLE_UP-(x) ) )
#define STEAMPAD_ANALOG_TRIGGER_THRESHOLD ( ( int )( STEAMPAD_MAX_ANALOGSAMPLE_TRIGGER * 0.5f ) )
#define STEAMPAD_ANALOG_PAD_THRESHOLD ( ( int )( STEAMPAD_MAX_ANALOGSAMPLE_MAX * 0.25f ) )
#define STEAMPAD_ANALOG_GYRO_THRESHOLD ( ( int ) ( STEAMPAD_MAX_ANALOGSAMPLE_GYRO * 0.3f ) )
#define STEAMPAD_DIGITAL_PAD_THRESHOLD ( ( int )( STEAMPAD_MAX_ANALOGSAMPLE_MAX * 0.52f ) )
#define STEAMPAD_AXIS_REPEAT_INTERVAL_START 0.6f
#define STEAMPAD_AXIS_REPEAT_INTERVAL_END 0.05f
#define STEAMPAD_AXIS_REPEAT_CURVE_TIME 1.75f
#define PAD_ANALOG_BUTTON_THRESHOLD ( ( int )( STEAMPAD_MAX_ANALOGSAMPLE_MAX * 0.285f ) )
#define PAD_ANALOG_BUTTON_THRESHOLD_STRONG ( ( int )( STEAMPAD_MAX_ANALOGSAMPLE_MAX * 0.68f ) )
#define SQRT2 1.414213562
// key translation
typedef struct
{
uint64 steampadinput;
ButtonCode_t steampadkey;
} steampadInputTosteampadKey_t;
static const int s_nSteamPadDeadZoneTable[] =
{
STEAMPAD_ANALOG_PAD_THRESHOLD, // LEFTPAD_AXIS_X
STEAMPAD_ANALOG_PAD_THRESHOLD, // LEFTPAD_AXIS_Y
STEAMPAD_ANALOG_PAD_THRESHOLD, // RIGHTPAD_AXIS_X
STEAMPAD_ANALOG_PAD_THRESHOLD, // RIGHTPAD_AXIS_Y
STEAMPAD_ANALOG_TRIGGER_THRESHOLD, //LEFT_TRIGGER_AXIS
STEAMPAD_ANALOG_TRIGGER_THRESHOLD, //RIGHT_TRIGGER_AXIS
STEAMPAD_ANALOG_GYRO_THRESHOLD, //GYRO_AXIS_PITCH
STEAMPAD_ANALOG_GYRO_THRESHOLD, //GYRO_AXIS_ROLL
STEAMPAD_ANALOG_GYRO_THRESHOLD, //GYRO_AXIS_YAW
};
//-----------------------------------------------------------------------------
// Purpose: Counts the number of active gamepads connected
//-----------------------------------------------------------------------------
uint32 CInputSystem::GetNumSteamControllersConnected()
{
return m_unNumConnected;
}
struct SDigitalMenuAction
{
const char *strName;
ButtonCode_t buttonCode;
ControllerDigitalActionHandle_t handle;
bool bState[STEAM_CONTROLLER_MAX_COUNT];
bool bAwaitingDebounce[STEAM_CONTROLLER_MAX_COUNT];
};
static SDigitalMenuAction g_DigitalMenuActions[] = {
{ "menu_left", STEAMCONTROLLER_DPAD_LEFT, 0, { false }, { false } },
{ "menu_right", STEAMCONTROLLER_DPAD_RIGHT, 0, { false }, { false } },
{ "menu_up", STEAMCONTROLLER_DPAD_UP, 0, { false }, { false } },
{ "menu_down", STEAMCONTROLLER_DPAD_DOWN, 0, { false }, { false } },
{ "menu_cancel", STEAMCONTROLLER_B, 0, { false }, { false } },
{ "menu_select", STEAMCONTROLLER_A, 0, { false }, { false } },
{ "resume_esc", STEAMCONTROLLER_START, 0, { false }, { false } },
{ "cl_trigger_first_notification", STEAMCONTROLLER_F1, 0, { false }, { false } }, // Command is in the in-game action set (use for hitting accept/ok on dialogs)
{ "cl_decline_first_notification", STEAMCONTROLLER_F2, 0, { false }, { false } }, // Command is in the in-game action set (use for hitting cancel/decline on dialogs)
{ "menu_toggle_function", STEAMCONTROLLER_Y, 0, { false }, { false }, }, // Command is in the in-game HUD action set
{ "menu_alt_function", STEAMCONTROLLER_X, 0, { false }, { false } }, // Command is in the in-game HUD action set
{ "cancelselect", STEAMCONTROLLER_START, 0, { false }, { false } }, // Command is in the in-game action set
{ "toggleready", STEAMCONTROLLER_F4, 0, { false }, { false } }, // Command is in the in-game action set
};
struct SAnalogAction
{
const char *strName;
JoystickAxis_t joystickAxisX, joystickAxisY;
ControllerAnalogActionHandle_t handle;
};
struct SGameActionSet
{
const char *strName;
GameActionSet_t eGameActionSet;
ControllerActionSetHandle_t handle;
};
static SGameActionSet g_GameActionSets[] = {
{ "MenuControls", GAME_ACTION_SET_MENUCONTROLS, 0 },
{ "FPSControls", GAME_ACTION_SET_FPSCONTROLS, 0 },
{ "InGameHUDControls", GAME_ACTION_SET_IN_GAME_HUD, 0 },
{ "SpectatorControls", GAME_ACTION_SET_SPECTATOR, 0 },
};
// Table that maps a physical steam controller origin to the corresponding character in our icon font.
// If the EControllerActionOrigin enum or the font changes, this table must be changed to match.
static const wchar_t* g_MapSteamControllerOriginToIconFont[] = {
L"", // k_EControllerActionOrigin_None
L"A", // k_EControllerActionOrigin_A
L"B", // k_EControllerActionOrigin_B
L"X", // k_EControllerActionOrigin_X
L"Y", // k_EControllerActionOrigin_Y
L"2", // k_EControllerActionOrigin_LeftBumper
L"3", // k_EControllerActionOrigin_RightBumper
L"(", // k_EControllerActionOrigin_LeftGrip
L")", // k_EControllerActionOrigin_RightGrip
L"5", // k_EControllerActionOrigin_Start
L"4", // k_EControllerActionOrigin_Back
L"q", // k_EControllerActionOrigin_LeftPad_Touch
L"w", // k_EControllerActionOrigin_LeftPad_Swipe
L"e", // k_EControllerActionOrigin_LeftPad_Click
L"a", // k_EControllerActionOrigin_LeftPad_DPadNorth
L"s", // k_EControllerActionOrigin_LeftPad_DPadSouth
L"d", // k_EControllerActionOrigin_LeftPad_DPadWest
L"f", // k_EControllerActionOrigin_LeftPad_DPadEast
L"y", // k_EControllerActionOrigin_RightPad_Touch
L"u", // k_EControllerActionOrigin_RightPad_Swipe
L"i", // k_EControllerActionOrigin_RightPad_Click
L"h", // k_EControllerActionOrigin_RightPad_DPadNorth
L"j", // k_EControllerActionOrigin_RightPad_DPadSouth
L"k", // k_EControllerActionOrigin_RightPad_DPadWest
L"l", // k_EControllerActionOrigin_RightPad_DEast
L"z", // k_EControllerActionOrigin_LeftTrigger_Pull
L"x", // k_EControllerActionOrigin_LeftTrigger_Click
L"n", // k_EControllerActionOrigin_RightTrigger_Pull
L"m", // k_EControllerActionOrigin_RightTrigger_Click
L"C", // k_EControllerActionOrigin_LeftStick_Move
L"V", // k_EControllerActionOrigin_LeftStick_Click
L"7", // k_EControllerActionOrigin_LeftStick_DPadNorth
L"8", // k_EControllerActionOrigin_LeftStick_DPadSouth
L"9", // k_EControllerActionOrigin_LeftStick_DPadWest
L"0", // k_EControllerActionOrigin_LeftStick_DPadEast
L"6", // k_EControllerActionOrigin_Gyro_Move
L"6", // k_EControllerActionOrigin_Gyro_Pitch
L"6", // k_EControllerActionOrigin_Gyro_Yaw
L"6", // k_EControllerActionOrigin_Gyro_Roll
};
// Table that maps a physical steam controller origin to a short description string for user display (only use this
// if it's impractical to use the icon font).
// If the EControllerActionOrigin enum changes, this table must be changed to match.
static const wchar_t* g_MapSteamControllerOriginToDescription[] = {
L"", // k_EControllerActionOrigin_None
L"A", // k_EControllerActionOrigin_A
L"B", // k_EControllerActionOrigin_B
L"X", // k_EControllerActionOrigin_X
L"Y", // k_EControllerActionOrigin_Y
L"LB", // k_EControllerActionOrigin_LeftBumper
L"RB", // k_EControllerActionOrigin_RightBumper
L"LG", // k_EControllerActionOrigin_LeftGrip
L"RG", // k_EControllerActionOrigin_RightGrip
L"START", // k_EControllerActionOrigin_Start
L"BACK", // k_EControllerActionOrigin_Back
L"LPTOUCH", // k_EControllerActionOrigin_LeftPad_Touch
L"LPSWIPE", // k_EControllerActionOrigin_LeftPad_Swipe
L"LPCLICK", // k_EControllerActionOrigin_LeftPad_Click
L"LPUP", // k_EControllerActionOrigin_LeftPad_DPadNorth
L"LPDOWN", // k_EControllerActionOrigin_LeftPad_DPadSouth
L"LPLEFT", // k_EControllerActionOrigin_LeftPad_DPadWest
L"LPRIGHT", // k_EControllerActionOrigin_LeftPad_DPadEast
L"RPTOUCH", // k_EControllerActionOrigin_RightPad_Touch
L"RPSWIPE", // k_EControllerActionOrigin_RightPad_Swipe
L"RPCLICK", // k_EControllerActionOrigin_RightPad_Click
L"RPUP", // k_EControllerActionOrigin_RightPad_DPadNorth
L"RPDOWN", // k_EControllerActionOrigin_RightPad_DPadSouth
L"RPLEFT", // k_EControllerActionOrigin_RightPad_DPadWest
L"RPRIGHT", // k_EControllerActionOrigin_RightPad_DEast
L"LT", // k_EControllerActionOrigin_LeftTrigger_Pull
L"LT", // k_EControllerActionOrigin_LeftTrigger_Click
L"LT", // k_EControllerActionOrigin_RightTrigger_Pull
L"LT", // k_EControllerActionOrigin_RightTrigger_Click
L"LS", // k_EControllerActionOrigin_LeftStick_Move
L"LSCLICK", // k_EControllerActionOrigin_LeftStick_Click
L"LSUP", // k_EControllerActionOrigin_LeftStick_DPadNorth
L"LSDOWN", // k_EControllerActionOrigin_LeftStick_DPadSouth
L"LSLEFT", // k_EControllerActionOrigin_LeftStick_DPadWest
L"LSRIGHT", // k_EControllerActionOrigin_LeftStick_DPadEast
L"GYRO", // k_EControllerActionOrigin_Gyro_Move
L"GYRO", // k_EControllerActionOrigin_Gyro_Pitch
L"GYRO", // k_EControllerActionOrigin_Gyro_Yaw
L"GYRO", // k_EControllerActionOrigin_Gyro_Roll
};
bool CInputSystem::InitializeSteamControllerActionSets()
{
auto psteamcontroller = g_pInputSystem->SteamControllerInterface();
if ( !psteamcontroller )
{
return false;
}
bool bGotHandles = true;
for ( int i = 0; i != ARRAYSIZE( g_DigitalMenuActions ); ++i )
{
g_DigitalMenuActions[i].handle = psteamcontroller->GetDigitalActionHandle( g_DigitalMenuActions[i].strName );
bGotHandles = bGotHandles && ( g_DigitalMenuActions[i].handle != 0 );
// Init the button state array
for( int j = 0; j < STEAM_CONTROLLER_MAX_COUNT; j++ )
{
g_DigitalMenuActions[i].bState[j] = false;
}
}
for ( int i = 0; i != ARRAYSIZE( g_GameActionSets ); ++i )
{
g_GameActionSets[i].handle = psteamcontroller->GetActionSetHandle( g_GameActionSets[i].strName );
bGotHandles = bGotHandles && g_GameActionSets[i].handle;
}
return bGotHandles;
}
ConVar sc_debug_sets( "sc_debug_sets", "0", FCVAR_ARCHIVE, "Debugging" );
void CInputSystem::PollSteamControllers( void )
{
// Make sure we've got the appropriate connections to Steam
auto steamcontroller = SteamControllerInterface();
if ( !steamcontroller )
{
return;
}
steamcontroller->RunFrame();
uint64 nControllerHandles[STEAM_CONTROLLER_MAX_COUNT];
m_unNumConnected = steamcontroller->GetConnectedControllers( nControllerHandles );
if ( m_unNumConnected > 0 )
{
if ( !m_bSteamControllerActionsInitialized )
{
// Retry initialization of controller actions if we didn't acquire them all before for some reason.
m_bSteamControllerActionsInitialized = m_bSteamController && InitializeSteamControllerActionSets();
g_pInputSystem->ActivateSteamControllerActionSet( GAME_ACTION_SET_MENUCONTROLS );
}
if ( m_bSteamControllerActionsInitialized )
{
// If we successfully initialized all the actions, and we have a connected controller, then we're considered "active".
m_bSteamControllerActive = true;
// For each digital action
for ( int i = 0; i != ARRAYSIZE( g_DigitalMenuActions ); ++i )
{
SDigitalMenuAction& action = g_DigitalMenuActions[i];
// and for each controller
for ( uint64 j = 0; j < m_unNumConnected; ++j )
{
// Get the action's current state
ControllerDigitalActionData_t data = steamcontroller->GetDigitalActionData( nControllerHandles[j], action.handle );
// We only care if the action is active
if ( data.bActive )
{
action.bAwaitingDebounce[j] = action.bAwaitingDebounce[j] && data.bState;
// If the action's state has changed
if ( data.bState != action.bState[j] )
{
action.bState[j] = data.bState;
// Press the key for the correct controller
ButtonCode_t buttonCode = ButtonCodeToJoystickButtonCode( action.buttonCode, j );
if ( action.bState[j] )
{
if ( !action.bAwaitingDebounce[j] )
{
PostButtonPressedEvent( IE_ButtonPressed, m_nLastSampleTick, buttonCode, buttonCode );
}
}
else
{
PostButtonReleasedEvent( IE_ButtonReleased, m_nLastSampleTick, buttonCode, buttonCode );
}
}
}
}
}
}
}
else
{
// If no controllers are connected, unflag the active state.
m_bSteamControllerActive = false;
}
}
bool CInputSystem::GetRadialMenuStickValues( int nSlot, float &fX, float &fY )
{
fX = m_pRadialMenuStickVal[nSlot][0];
fY = m_pRadialMenuStickVal[nSlot][1];
return true;
}
bool CInputSystem::IsSteamControllerActive( void )
{
return m_bSteamControllerActive;
}
bool CInputSystem::InitializeSteamControllers()
{
m_flLastSteamControllerInput = -FLT_MAX;
auto steamcontroller = SteamControllerInterface();
if ( steamcontroller )
{
if ( !steamcontroller->Init() )
{
return false;
}
}
else
{
return false;
}
for( int i=0; i<STEAM_CONTROLLER_MAX_COUNT; i++ )
{
m_pRadialMenuStickVal[i][0] = 0.0f;
m_pRadialMenuStickVal[i][1] = 0.0f;
}
// We have to account for other joysticks prior to adding steam controllers
// So we get the baseline number here when first initializing
m_nJoystickBaseline = m_nJoystickCount;
if ( steamcontroller )
{
uint64 nControllerHandles[STEAM_CONTROLLER_MAX_COUNT];
m_unNumConnected = steamcontroller->GetConnectedControllers( nControllerHandles );
steamcontroller->RunFrame();
if ( m_unNumConnected > 0 )
{
for ( uint32 i = 0; i < m_unNumConnected; i++ )
{
if ( m_Device[i].m_nJoystickIndex == INVALID_USER_ID )
{
int nJoystickIndex = i;
m_Device[i].m_nJoystickIndex = nJoystickIndex;
m_Device[i].m_nHardwareIndex = i;
}
m_nControllerType[m_Device[i].m_nJoystickIndex] = INPUT_TYPE_STEAMCONTROLLER;
}
}
return true;
}
return false;
}
ControllerActionSetHandle_t CInputSystem::GetActionSetHandle( GameActionSet_t eActionSet )
{
return g_GameActionSets[eActionSet].handle;
}
ControllerActionSetHandle_t CInputSystem::GetActionSetHandle( const char* szActionSet )
{
for ( int i = 0; i != ARRAYSIZE( g_GameActionSets ); ++i )
{
if ( !Q_strcmp( szActionSet, g_GameActionSets[i].strName ) )
{
return g_GameActionSets[i].handle;
}
}
return 0;
}
void CInputSystem::ActivateSteamControllerActionSetForSlot( uint64 nSlot, GameActionSet_t eActionSet )
{
auto steamcontroller = SteamControllerInterface();
bool bChangedActionSet = false;
if ( steamcontroller )
{
if ( nSlot == STEAM_CONTROLLER_HANDLE_ALL_CONTROLLERS )
{
for ( int i = 0; i < STEAM_CONTROLLER_MAX_COUNT; i++ )
{
if ( m_currentActionSet[i] != eActionSet )
{
bChangedActionSet = true;
m_currentActionSet[i] = eActionSet;
}
}
steamcontroller->ActivateActionSet( STEAM_CONTROLLER_HANDLE_ALL_CONTROLLERS, g_GameActionSets[eActionSet].handle );
}
else
{
uint64 nControllerHandles[STEAM_CONTROLLER_MAX_COUNT];
int unNumConnected = steamcontroller->GetConnectedControllers( nControllerHandles );
if( nSlot < unNumConnected )
{
if ( m_currentActionSet[nSlot] != eActionSet )
{
bChangedActionSet = true;
m_currentActionSet[nSlot] = eActionSet;
}
steamcontroller->ActivateActionSet( nControllerHandles[nSlot], g_GameActionSets[eActionSet].handle );
}
}
}
if ( bChangedActionSet )
{
// If we changed action set, then flag everything for a debounce (meaning we demand to see an unpressed state before we'll register a pressed one)
for ( int i = 0; i < STEAM_CONTROLLER_MAX_COUNT; i++ )
{
for ( int j = 0; j != ARRAYSIZE( g_DigitalMenuActions ); ++j )
{
g_DigitalMenuActions[j].bAwaitingDebounce[i] = true;
}
}
}
}
const int CInputSystem::GetSteamPadDeadZone( ESteamPadAxis axis )
{
int nDeadzone = s_nSteamPadDeadZoneTable[ axis ];
// Do modifications if required here?
return nDeadzone;
}
//-----------------------------------------------------------------------------
// Purpose: Processes data for controller
//-----------------------------------------------------------------------------
void CInputSystem::ReadSteamController( int iIndex )
{
}
//-----------------------------------------------------------------------------
// Purpose: Pulse haptic feedback
//-----------------------------------------------------------------------------
/* void CInputSystem::PulseHapticOnSteamController( uint32 nControllerIndex, ESteamControllerPad ePad, unsigned short durationMicroSec )
{
auto steamcontroller = SteamControllerInterface();
if ( steamcontroller )
{
steamcontroller->TriggerHapticPulse( nControllerIndex, ePad, durationMicroSec );
}
}*/
//-----------------------------------------------------------------------------
// Purpose: Returns the controller State for a particular joystick slot
//-----------------------------------------------------------------------------
bool CInputSystem::GetControllerStateForSlot( int nSlot )
{
return false;
}
int CInputSystem::GetSteamControllerIndexForSlot( int nSlot )
{
for ( int i = 0; i < Q_ARRAYSIZE( m_Device ); i++ )
{
if ( m_Device[i].active && (int)m_Device[i].m_nJoystickIndex == nSlot )
{
return m_Device[i].m_nHardwareIndex;
}
}
return -1;
}
//-----------------------------------------------------------------------------
// Purpose: Post events, ignoring key repeats
//-----------------------------------------------------------------------------
void CInputSystem::PostKeyEvent( int iIndex, sKey_t sKey, int nSample )
{
// Rework of xbox code here :
AnalogCode_t code = ANALOG_CODE_LAST;
float value = 0.f;
//int nMsgSlot = iIndex;
int nMsgSlot = m_Device[iIndex].m_nJoystickIndex;
int nSampleThreshold = 1;
// Look for changes on the analog axes
switch( sKey )
{
case SK_BUTTON_LPAD_LEFT:
case SK_BUTTON_LPAD_RIGHT:
{
code = (AnalogCode_t)JOYSTICK_AXIS( nMsgSlot, JOY_AXIS_X );
value = ( sKey == SK_BUTTON_LPAD_LEFT ) ? -nSample : nSample;
// Kind of a hack to horizontal values for menu selection items in Portal 2
// The additional 5k helps accidental horizontals in menus.
nSampleThreshold = ( int )( STEAMPAD_DIGITAL_PAD_THRESHOLD ) + 5000;
}
break;
case SK_BUTTON_LPAD_UP:
case SK_BUTTON_LPAD_DOWN:
{
code = (AnalogCode_t)JOYSTICK_AXIS( nMsgSlot, JOY_AXIS_Y );
value = ( sKey == SK_BUTTON_LPAD_UP ) ? -nSample : nSample;
nSampleThreshold = ( int )( STEAMPAD_DIGITAL_PAD_THRESHOLD );
}
break;
case SK_BUTTON_RPAD_LEFT:
case SK_BUTTON_RPAD_RIGHT:
{
code = (AnalogCode_t)JOYSTICK_AXIS( nMsgSlot, JOY_AXIS_U );
value = ( sKey == SK_BUTTON_RPAD_LEFT ) ? -nSample : nSample;
// Kind of a hack to horizontal values for menu selection items in Portal 2
// The additional 5k helps accidental horizontals in menus.
nSampleThreshold = ( int )( STEAMPAD_DIGITAL_PAD_THRESHOLD ) + 5000;;
}
break;
case SK_BUTTON_RPAD_UP:
case SK_BUTTON_RPAD_DOWN:
{
code = (AnalogCode_t)JOYSTICK_AXIS( nMsgSlot, JOY_AXIS_R );
value = ( sKey == SK_BUTTON_RPAD_UP ) ? -nSample : nSample;
nSampleThreshold = ( int )( STEAMPAD_DIGITAL_PAD_THRESHOLD );
}
break;
}
// Store the analog event
if ( ANALOG_CODE_LAST != code )
{
InputState_t &state = m_InputState[ m_bIsPolling ];
state.m_pAnalogDelta[ code ] = ( int )( value - state.m_pAnalogValue[ code ] );
state.m_pAnalogValue[ code ] = ( int )value;
if ( state.m_pAnalogDelta[ code ] != 0 )
{
PostEvent( IE_AnalogValueChanged, m_nLastSampleTick, code, ( int )value, state.m_pAnalogDelta[ code ] );
}
}
// store the key
m_Device[iIndex].m_appSKeys[sKey].sample = nSample;
if ( nSample > nSampleThreshold )
{
m_Device[iIndex].m_appSKeys[sKey].repeats++;
}
else
{
m_Device[iIndex].m_appSKeys[sKey].repeats = 0;
nSample = 0;
}
if ( m_Device[iIndex].m_appSKeys[sKey].repeats > 1 )
{
// application cannot handle streaming keys
// first keypress is the only edge trigger
return;
}
// package the key
ButtonCode_t buttonCode = SKeyToButtonCode( nMsgSlot, sKey );
if ( nSample )
{
PostButtonPressedEvent( IE_ButtonPressed, m_nLastSampleTick, buttonCode, buttonCode );
}
else
{
PostButtonReleasedEvent( IE_ButtonReleased, m_nLastSampleTick, buttonCode, buttonCode );
}
}
// Gets the action origin (i.e. which physical input) maps to the given virtual button for the given action set
EControllerActionOrigin CInputSystem::GetSteamControllerActionOrigin( const char* action, GameActionSet_t action_set )
{
auto pSC = SteamControllerInterface();
if ( pSC )
{
ControllerHandle_t hConnected[STEAM_CONTROLLER_MAX_COUNT];
auto nConnected = pSC->GetConnectedControllers( hConnected );
if ( nConnected == 0 )
{
return k_EControllerActionOrigin_None;
}
SGameActionSet* pActionSet = nullptr;
for ( int i = 0; i < ARRAYSIZE( g_GameActionSets ); i++ )
{
if ( g_GameActionSets[i].eGameActionSet == action_set )
{
pActionSet = &g_GameActionSets[i];
break;
}
}
if ( pActionSet )
{
auto actionHandle = pSC->GetDigitalActionHandle( action );
EControllerActionOrigin origins[STEAM_CONTROLLER_MAX_ORIGINS];
int nOrigins = pSC->GetDigitalActionOrigins( hConnected[0], pActionSet->handle, actionHandle, origins );
if ( nOrigins > 0 )
{
return origins[0];
}
}
}
return k_EControllerActionOrigin_None;
}
// Gets the action origin (i.e. which physical input) maps to the given virtual button for the given action set
EControllerActionOrigin CInputSystem::GetSteamControllerActionOrigin( const char* action, ControllerActionSetHandle_t action_set_handle )
{
auto pSC = SteamControllerInterface();
if ( pSC && action_set_handle )
{
ControllerHandle_t hConnected[STEAM_CONTROLLER_MAX_COUNT];
auto nConnected = pSC->GetConnectedControllers( hConnected );
if ( nConnected == 0 )
{
return k_EControllerActionOrigin_None;
}
auto actionHandle = pSC->GetDigitalActionHandle( action );
EControllerActionOrigin origins[STEAM_CONTROLLER_MAX_ORIGINS];
int nOrigins = pSC->GetDigitalActionOrigins( hConnected[0], action_set_handle, actionHandle, origins );
if ( nOrigins > 0 )
{
return origins[0];
}
}
return k_EControllerActionOrigin_None;
}
// Maps a Steam Controller action origin to a string (consisting of a single character) in our SC icon font
const wchar_t* CInputSystem::GetSteamControllerFontCharacterForActionOrigin( EControllerActionOrigin origin )
{
if ( origin >= 0 && origin < ARRAYSIZE( g_MapSteamControllerOriginToIconFont ) )
{
return g_MapSteamControllerOriginToIconFont[origin];
}
else
{
return L"";
}
}
// Maps a Steam Controller action origin to a short text string (e.g. "X", "LB", "LDOWN") describing the control.
// Prefer to actually use the icon font wherever possible.
const wchar_t* CInputSystem::GetSteamControllerDescriptionForActionOrigin( EControllerActionOrigin origin )
{
if ( origin >= 0 && origin < ARRAYSIZE( g_MapSteamControllerOriginToDescription ) )
{
return g_MapSteamControllerOriginToDescription[origin];
}
else
{
return L"";
}
}