From d27f95b7669d8049520f42dbb1b30c828c425a72 Mon Sep 17 00:00:00 2001 From: EnderZip Date: Mon, 25 Oct 2021 17:44:28 +0700 Subject: [PATCH] ported inputsystem.dll --- inputsystem/Xbox/xbox.def | 3 + inputsystem/inputsystem.cpp | 1561 +++++++++++++++++++++++++++++++ inputsystem/inputsystem.h | 471 ++++++++++ inputsystem/inputsystem.vpc | 74 ++ inputsystem/joystick_sdl.cpp | 615 ++++++++++++ inputsystem/key_translation.cpp | 911 ++++++++++++++++++ inputsystem/key_translation.h | 38 + inputsystem/novint.cpp | 138 +++ inputsystem/posix_stubs.h | 75 ++ inputsystem/steamcontroller.cpp | 698 ++++++++++++++ lib/common/SDL2.lib | Bin 0 -> 168866 bytes lib/common/glfw3.lib | Bin 488880 -> 0 bytes lib/public/SDL2.lib | Bin 0 -> 168866 bytes public/inputsystem/InputEnums.h | 113 ++- public/steam/isteamcontroller.h | 262 ++++-- 15 files changed, 4855 insertions(+), 104 deletions(-) create mode 100644 inputsystem/Xbox/xbox.def create mode 100644 inputsystem/inputsystem.cpp create mode 100644 inputsystem/inputsystem.h create mode 100644 inputsystem/inputsystem.vpc create mode 100644 inputsystem/joystick_sdl.cpp create mode 100644 inputsystem/key_translation.cpp create mode 100644 inputsystem/key_translation.h create mode 100644 inputsystem/novint.cpp create mode 100644 inputsystem/posix_stubs.h create mode 100644 inputsystem/steamcontroller.cpp create mode 100644 lib/common/SDL2.lib delete mode 100644 lib/common/glfw3.lib create mode 100644 lib/public/SDL2.lib diff --git a/inputsystem/Xbox/xbox.def b/inputsystem/Xbox/xbox.def new file mode 100644 index 0000000..c0524b6 --- /dev/null +++ b/inputsystem/Xbox/xbox.def @@ -0,0 +1,3 @@ +LIBRARY inputsystem_360.dll +EXPORTS + CreateInterface @1 diff --git a/inputsystem/inputsystem.cpp b/inputsystem/inputsystem.cpp new file mode 100644 index 0000000..0ea1463 --- /dev/null +++ b/inputsystem/inputsystem.cpp @@ -0,0 +1,1561 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//===========================================================================// + +#include "inputsystem.h" +#include "key_translation.h" +#include "inputsystem/ButtonCode.h" +#include "inputsystem/AnalogCode.h" +#include "tier0/etwprof.h" +#include "tier1/convar.h" +#include "tier0/icommandline.h" + +#if defined( USE_SDL ) +#undef M_PI +#include "SDL.h" +static void initKeymap(void); +#endif + +#ifdef _X360 +#include "xbox/xbox_win32stubs.h" +#endif + +#include "../thirdparty/imgui/imgui.h" +#include "../thirdparty/imgui/imgui_impl_win32.h" + +ConVar joy_xcontroller_found( "joy_xcontroller_found", "1", FCVAR_HIDDEN, "Automatically set to 1 if an xcontroller has been detected." ); + +//----------------------------------------------------------------------------- +// Singleton instance +//----------------------------------------------------------------------------- +static CInputSystem g_InputSystem; +EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CInputSystem, IInputSystem, + INPUTSYSTEM_INTERFACE_VERSION, g_InputSystem ); + + + +#if defined( WIN32 ) && !defined( _X360 ) +typedef BOOL (WINAPI *RegisterRawInputDevices_t) +( + PCRAWINPUTDEVICE pRawInputDevices, + UINT uiNumDevices, + UINT cbSize +); + +typedef UINT (WINAPI *GetRawInputData_t) +( + HRAWINPUT hRawInput, + UINT uiCommand, + LPVOID pData, + PUINT pcbSize, + UINT cbSizeHeader +); + +RegisterRawInputDevices_t pfnRegisterRawInputDevices; +GetRawInputData_t pfnGetRawInputData; +#endif + + + +//----------------------------------------------------------------------------- +// Constructor, destructor +//----------------------------------------------------------------------------- +CInputSystem::CInputSystem() +{ + m_nLastPollTick = m_nLastSampleTick = m_StartupTimeTick = 0; + m_ChainedWndProc = 0; + m_hAttachedHWnd = 0; + m_hEvent = NULL; + m_bEnabled = true; + m_bPumpEnabled = true; + m_bIsPolling = false; + m_JoysticksEnabled.ClearAllFlags(); + m_nJoystickCount = 0; + m_bJoystickInitialized = false; + m_nPollCount = 0; + m_PrimaryUserId = INVALID_USER_ID; + m_uiMouseWheel = 0; + m_bXController = false; + m_bRawInputSupported = false; + m_bSteamController = false; + m_bSteamControllerActionsInitialized = false; + m_bSteamControllerActive = false; + + Assert( (MAX_JOYSTICKS + 7) >> 3 << sizeof(unsigned short) ); + + m_pXInputDLL = NULL; + m_pRawInputDLL = NULL; + +#if defined ( _WIN32 ) && !defined ( _X360 ) + // NVNT DLL + m_pNovintDLL = NULL; +#endif + + m_bConsoleTextMode = false; + m_bSkipControllerInitialization = false; + + if ( CommandLine()->CheckParm( "-nosteamcontroller" ) ) + { + m_bSkipControllerInitialization = true; + } +} + +CInputSystem::~CInputSystem() +{ + if ( m_pXInputDLL ) + { + Sys_UnloadModule( m_pXInputDLL ); + m_pXInputDLL = NULL; + } + + if ( m_pRawInputDLL ) + { + Sys_UnloadModule( m_pRawInputDLL ); + m_pRawInputDLL = NULL; + } + +#if defined ( _WIN32 ) && !defined ( _X360 ) + // NVNT DLL unload + if ( m_pNovintDLL ) + { + Sys_UnloadModule( m_pNovintDLL ); + m_pNovintDLL = NULL; + } +#endif +} + + +//----------------------------------------------------------------------------- +// Initialization +//----------------------------------------------------------------------------- +InitReturnVal_t CInputSystem::Init() +{ + InitReturnVal_t nRetVal = BaseClass::Init(); + if ( nRetVal != INIT_OK ) + return nRetVal; + + m_StartupTimeTick = Plat_MSTime(); + + +#if !defined( POSIX ) + if ( IsPC() ) + { + m_uiMouseWheel = RegisterWindowMessage( "MSWHEEL_ROLLMSG" ); + } + + m_hEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); + if ( !m_hEvent ) + return INIT_FAILED; +#endif + + // Initialize the input system copy of the steam API context, for use by controller stuff (don't do this if we're a dedicated server). + if ( !m_bSkipControllerInitialization && SteamAPI_InitSafe() ) + { + m_SteamAPIContext.Init(); + if ( m_SteamAPIContext.SteamController() ) + { + m_SteamAPIContext.SteamController()->Init(); + m_bSteamController = InitializeSteamControllers(); + m_bSteamControllerActionsInitialized = m_bSteamController && InitializeSteamControllerActionSets(); + if ( m_bSteamControllerActionsInitialized ) + { + //ActivateSteamControllerActionSet( GAME_ACTION_SET_MENUCONTROLS ); + } + } + } + + ButtonCode_InitKeyTranslationTable(); + ButtonCode_UpdateScanCodeLayout(); + + joy_xcontroller_found.SetValue( 0 ); + if ( IsPC() && !m_bConsoleTextMode ) + { + InitializeJoysticks(); + if ( m_bXController ) + joy_xcontroller_found.SetValue( 1 ); + + +#if defined( PLATFORM_WINDOWS_PC ) + // NVNT try and load and initialize through the haptic dll, but only if the drivers are installed + HMODULE hdl = LoadLibraryEx( "hdl.dll", NULL, LOAD_LIBRARY_AS_DATAFILE ); + + if ( hdl ) + { + m_pNovintDLL = Sys_LoadModule( "haptics.dll" ); + if ( m_pNovintDLL ) + { + InitializeNovintDevices(); + } + FreeLibrary( hdl ); + } +#endif + } + +#if defined( _X360 ) + SetPrimaryUserId( XBX_GetPrimaryUserId() ); + InitializeXDevices(); + m_bXController = true; +#endif + +#if defined( USE_SDL ) + + m_bRawInputSupported = true; + initKeymap(); + +#elif defined( WIN32 ) && !defined( _X360 ) + + // Check if this version of windows supports raw mouse input (later than win2k) + m_bRawInputSupported = false; + + CSysModule *m_pRawInputDLL = Sys_LoadModule( "USER32.dll" ); + if ( m_pRawInputDLL ) + { + pfnRegisterRawInputDevices = (RegisterRawInputDevices_t)GetProcAddress( (HMODULE)m_pRawInputDLL, "RegisterRawInputDevices" ); + pfnGetRawInputData = (GetRawInputData_t)GetProcAddress( (HMODULE)m_pRawInputDLL, "GetRawInputData" ); + if ( pfnRegisterRawInputDevices && pfnGetRawInputData ) + m_bRawInputSupported = true; + } + +#endif + + return INIT_OK; +} + +bool CInputSystem::Connect( CreateInterfaceFn factory ) +{ + if ( !BaseClass::Connect( factory ) ) + return false; + +#if defined( USE_SDL ) + m_pLauncherMgr = (ILauncherMgr *)factory( SDLMGR_INTERFACE_VERSION, NULL ); +#endif + + return true; +} + + +//----------------------------------------------------------------------------- +// Shutdown +//----------------------------------------------------------------------------- +void CInputSystem::Shutdown() +{ +#if !defined( POSIX ) + if ( m_hEvent != NULL ) + { + CloseHandle( m_hEvent ); + m_hEvent = NULL; + } +#endif + + if ( IsPC() ) + { + ShutdownJoysticks(); + } + + BaseClass::Shutdown(); +} + + +//----------------------------------------------------------------------------- +// Sleep until input +//----------------------------------------------------------------------------- +void CInputSystem::SleepUntilInput( int nMaxSleepTimeMS ) +{ +#if defined( _WIN32 ) && !defined( USE_SDL ) + if ( nMaxSleepTimeMS < 0 ) + { + nMaxSleepTimeMS = INFINITE; + } + + MsgWaitForMultipleObjects( 1, &m_hEvent, FALSE, nMaxSleepTimeMS, QS_ALLEVENTS ); +#elif defined( USE_SDL ) + m_pLauncherMgr->WaitUntilUserInput( nMaxSleepTimeMS ); +#else +#warning "need a SleepUntilInput impl" +#endif +} + + + +//----------------------------------------------------------------------------- +// Callback to call into our class +//----------------------------------------------------------------------------- +#if defined( PLATFORM_WINDOWS ) +static LRESULT CALLBACK InputSystemWindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) +{ + return g_InputSystem.WindowProc( hwnd, uMsg, wParam, lParam ); +} +#endif + + +//----------------------------------------------------------------------------- +// Hooks input listening up to a window +//----------------------------------------------------------------------------- +void CInputSystem::AttachToWindow( void* hWnd ) +{ + Assert( m_hAttachedHWnd == 0 ); + if ( m_hAttachedHWnd ) + { + Warning( "CInputSystem::AttachToWindow: Cannot attach to two windows at once!\n" ); + return; + } + +#if defined( PLATFORM_WINDOWS ) + m_ChainedWndProc = (WNDPROC)GetWindowLongPtrW( (HWND)hWnd, GWLP_WNDPROC ); + SetWindowLongPtrW( (HWND)hWnd, GWLP_WNDPROC, (LONG_PTR)InputSystemWindowProc ); +#endif + + m_hAttachedHWnd = (HWND)hWnd; + +#if defined( PLATFORM_WINDOWS_PC ) && !defined( USE_SDL ) + // NVNT inform novint devices of window + AttachWindowToNovintDevices( hWnd ); + + // register to read raw mouse input + +#if !defined(HID_USAGE_PAGE_GENERIC) +#define HID_USAGE_PAGE_GENERIC ((USHORT) 0x01) +#endif +#if !defined(HID_USAGE_GENERIC_MOUSE) +#define HID_USAGE_GENERIC_MOUSE ((USHORT) 0x02) +#endif + + if ( m_bRawInputSupported ) + { + RAWINPUTDEVICE Rid[1]; + Rid[0].usUsagePage = HID_USAGE_PAGE_GENERIC; + Rid[0].usUsage = HID_USAGE_GENERIC_MOUSE; + Rid[0].dwFlags = RIDEV_INPUTSINK; + Rid[0].hwndTarget = g_InputSystem.m_hAttachedHWnd; // GetHhWnd; + pfnRegisterRawInputDevices(Rid, ARRAYSIZE(Rid), sizeof(Rid[0])); + } +#endif + + // New window, clear input state + ClearInputState(); +} + + +//----------------------------------------------------------------------------- +// Unhooks input listening from a window +//----------------------------------------------------------------------------- +void CInputSystem::DetachFromWindow( ) +{ + if ( !m_hAttachedHWnd ) + return; + + ResetInputState(); + +#if defined( PLATFORM_WINDOWS ) + if ( m_ChainedWndProc ) + { + SetWindowLongPtrW( m_hAttachedHWnd, GWLP_WNDPROC, (LONG_PTR)m_ChainedWndProc ); + m_ChainedWndProc = 0; + } +#endif + +#if defined( PLATFORM_WINDOWS_PC ) + // NVNT inform novint devices loss of window + DetachWindowFromNovintDevices( ); +#endif + m_hAttachedHWnd = 0; +} + + +//----------------------------------------------------------------------------- +// Enables/disables input +//----------------------------------------------------------------------------- +void CInputSystem::EnableInput( bool bEnable ) +{ + m_bEnabled = bEnable; +} + + +//----------------------------------------------------------------------------- +// Enables/disables the inputsystem windows message pump +//----------------------------------------------------------------------------- +void CInputSystem::EnableMessagePump( bool bEnable ) +{ + m_bPumpEnabled = bEnable; +} + + +//----------------------------------------------------------------------------- +// Clears the input state, doesn't generate key-up messages +//----------------------------------------------------------------------------- +void CInputSystem::ClearInputState() +{ + for ( int i = 0; i < INPUT_STATE_COUNT; ++i ) + { + InputState_t& state = m_InputState[i]; + state.m_ButtonState.ClearAll(); + memset( state.m_pAnalogDelta, 0, ANALOG_CODE_LAST * sizeof(int) ); + memset( state.m_pAnalogValue, 0, ANALOG_CODE_LAST * sizeof(int) ); + memset( state.m_ButtonPressedTick, 0, BUTTON_CODE_LAST * sizeof(int) ); + memset( state.m_ButtonReleasedTick, 0, BUTTON_CODE_LAST * sizeof(int) ); + state.m_Events.Purge(); + state.m_bDirty = false; + } + memset( m_appXKeys, 0, XUSER_MAX_COUNT * XK_MAX_KEYS * sizeof(appKey_t) ); +} + +//----------------------------------------------------------------------------- +// Resets the input state +//----------------------------------------------------------------------------- +void CInputSystem::ResetInputState() +{ + ReleaseAllButtons(); + ZeroAnalogState( 0, ANALOG_CODE_LAST - 1 ); + memset( m_appXKeys, 0, XUSER_MAX_COUNT * XK_MAX_KEYS * sizeof(appKey_t) ); + + m_mouseRawAccumX = m_mouseRawAccumY = 0; +} + + +//----------------------------------------------------------------------------- +// Convert back + forth between ButtonCode/AnalogCode + strings +//----------------------------------------------------------------------------- +const char *CInputSystem::ButtonCodeToString( ButtonCode_t code ) const +{ + return ButtonCode_ButtonCodeToString( code, m_bXController ); +} + +const char *CInputSystem::AnalogCodeToString( AnalogCode_t code ) const +{ + return AnalogCode_AnalogCodeToString( code ); +} + +ButtonCode_t CInputSystem::StringToButtonCode( const char *pString ) const +{ + return ButtonCode_StringToButtonCode( pString, m_bXController ); +} + +AnalogCode_t CInputSystem::StringToAnalogCode( const char *pString ) const +{ + return AnalogCode_StringToAnalogCode( pString ); +} + + +//----------------------------------------------------------------------------- +// Convert back + forth between virtual codes + button codes +// FIXME: This is a temporary piece of code +//----------------------------------------------------------------------------- +ButtonCode_t CInputSystem::VirtualKeyToButtonCode( int nVirtualKey ) const +{ + return ButtonCode_VirtualKeyToButtonCode( nVirtualKey ); +} + +int CInputSystem::ButtonCodeToVirtualKey( ButtonCode_t code ) const +{ + return ButtonCode_ButtonCodeToVirtualKey( code ); +} + +ButtonCode_t CInputSystem::XKeyToButtonCode( int nPort, int nXKey ) const +{ + if ( m_bXController ) + return ButtonCode_XKeyToButtonCode( nPort, nXKey ); + return KEY_NONE; +} + +ButtonCode_t CInputSystem::ScanCodeToButtonCode( int lParam ) const +{ + return ButtonCode_ScanCodeToButtonCode( lParam ); +} + +ButtonCode_t CInputSystem::SKeyToButtonCode( int nPort, int nXKey ) const +{ + return ButtonCode_SKeyToButtonCode( nPort, nXKey ); +} + +//----------------------------------------------------------------------------- +// Post an event to the queue +//----------------------------------------------------------------------------- +void CInputSystem::PostEvent( int nType, int nTick, int nData, int nData2, int nData3 ) +{ + InputEvent_t event; + + memset( &event, 0, sizeof(event) ); + event.m_nType = nType; + event.m_nTick = nTick; + event.m_nData = nData; + event.m_nData2 = nData2; + event.m_nData3 = nData3; + + PostUserEvent( event ); +} + + +//----------------------------------------------------------------------------- +// Post an button press event to the queue +//----------------------------------------------------------------------------- +void CInputSystem::PostButtonPressedEvent( InputEventType_t nType, int nTick, ButtonCode_t scanCode, ButtonCode_t virtualCode ) +{ + InputState_t &state = m_InputState[ m_bIsPolling ]; + if ( !state.m_ButtonState.IsBitSet( scanCode ) ) + { + // Update button state + state.m_ButtonState.Set( scanCode ); + state.m_ButtonPressedTick[ scanCode ] = nTick; + + // Add this event to the app-visible event queue + PostEvent( nType, nTick, scanCode, virtualCode ); + +#if defined( _X360 ) + // FIXME: Remove! Fake a windows message for vguimatsurface's input handler + if ( IsJoystickCode( scanCode ) ) + { + ProcessEvent( WM_XCONTROLLER_KEY, scanCode, 1 ); + } +#endif + } +} + + +//----------------------------------------------------------------------------- +// Post an button release event to the queue +//----------------------------------------------------------------------------- +void CInputSystem::PostButtonReleasedEvent( InputEventType_t nType, int nTick, ButtonCode_t scanCode, ButtonCode_t virtualCode ) +{ + InputState_t &state = m_InputState[ m_bIsPolling ]; + if ( state.m_ButtonState.IsBitSet( scanCode ) ) + { + // Update button state + state.m_ButtonState.Clear( scanCode ); + state.m_ButtonReleasedTick[ scanCode ] = nTick; + + // Add this event to the app-visible event queue + PostEvent( nType, nTick, scanCode, virtualCode ); + +#if defined( _X360 ) + // FIXME: Remove! Fake a windows message for vguimatsurface's input handler + if ( IsJoystickCode( scanCode ) ) + { + ProcessEvent( WM_XCONTROLLER_KEY, scanCode, 0 ); + } +#endif + } +} + + +//----------------------------------------------------------------------------- +// Purpose: Pass Joystick button events through the engine's window procs +//----------------------------------------------------------------------------- +void CInputSystem::ProcessEvent( UINT uMsg, WPARAM wParam, LPARAM lParam ) +{ +#if !defined( POSIX ) + // To prevent subtle input timing bugs, all button events must be fed + // through the window proc once per frame, same as the keyboard and mouse. + HWND hWnd = GetFocus(); + WNDPROC windowProc = (WNDPROC)GetWindowLongPtrW(hWnd, GWLP_WNDPROC ); + if ( windowProc ) + { + windowProc( hWnd, uMsg, wParam, lParam ); + } +#endif +} + + +//----------------------------------------------------------------------------- +// Copies the input state record over +//----------------------------------------------------------------------------- +void CInputSystem::CopyInputState( InputState_t *pDest, const InputState_t &src, bool bCopyEvents ) +{ + pDest->m_Events.RemoveAll(); + pDest->m_bDirty = false; + if ( src.m_bDirty ) + { + pDest->m_ButtonState = src.m_ButtonState; + memcpy( &pDest->m_ButtonPressedTick, &src.m_ButtonPressedTick, sizeof( pDest->m_ButtonPressedTick ) ); + memcpy( &pDest->m_ButtonReleasedTick, &src.m_ButtonReleasedTick, sizeof( pDest->m_ButtonReleasedTick ) ); + memcpy( &pDest->m_pAnalogDelta, &src.m_pAnalogDelta, sizeof( pDest->m_pAnalogDelta ) ); + memcpy( &pDest->m_pAnalogValue, &src.m_pAnalogValue, sizeof( pDest->m_pAnalogValue ) ); + if ( bCopyEvents ) + { + if ( src.m_Events.Count() > 0 ) + { + pDest->m_Events.EnsureCount( src.m_Events.Count() ); + memcpy( pDest->m_Events.Base(), src.m_Events.Base(), src.m_Events.Count() * sizeof(InputEvent_t) ); + } + } + } +} + + +#if defined( PLATFORM_WINDOWS_PC ) +void CInputSystem::PollInputState_Windows() +{ + if ( m_bPumpEnabled ) + { + // Poll mouse + keyboard + MSG msg; + while ( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) ) + { + if ( msg.message == WM_QUIT ) + { + PostEvent( IE_Quit, m_nLastSampleTick ); + break; + } + + TranslateMessage( &msg ); + DispatchMessage( &msg ); + } + + // NOTE: Under some implementations of Win9x, + // dispatching messages can cause the FPU control word to change + SetupFPUControlWord(); + } +} +#endif + +#if defined( USE_SDL ) + +static BYTE scantokey[SDL_NUM_SCANCODES]; + +static void initKeymap(void) +{ + memset(scantokey, '\0', sizeof (scantokey)); + + for (int i = SDL_SCANCODE_A; i <= SDL_SCANCODE_Z; i++) + scantokey[i] = KEY_A + (i - SDL_SCANCODE_A); + for (int i = SDL_SCANCODE_1; i <= SDL_SCANCODE_9; i++) + scantokey[i] = KEY_1 + (i - SDL_SCANCODE_1); + for (int i = SDL_SCANCODE_F1; i <= SDL_SCANCODE_F12; i++) + scantokey[i] = KEY_F1 + (i - SDL_SCANCODE_F1); + for (int i = SDL_SCANCODE_KP_1; i <= SDL_SCANCODE_KP_9; i++) + scantokey[i] = KEY_PAD_1 + (i - SDL_SCANCODE_KP_1); + + scantokey[SDL_SCANCODE_0] = KEY_0; + scantokey[SDL_SCANCODE_KP_0] = KEY_PAD_0; + scantokey[SDL_SCANCODE_RETURN] = KEY_ENTER; + scantokey[SDL_SCANCODE_ESCAPE] = KEY_ESCAPE; + scantokey[SDL_SCANCODE_BACKSPACE] = KEY_BACKSPACE; + scantokey[SDL_SCANCODE_TAB] = KEY_TAB; + scantokey[SDL_SCANCODE_SPACE] = KEY_SPACE; + scantokey[SDL_SCANCODE_MINUS] = KEY_MINUS; + scantokey[SDL_SCANCODE_EQUALS] = KEY_EQUAL; + scantokey[SDL_SCANCODE_LEFTBRACKET] = KEY_LBRACKET; + scantokey[SDL_SCANCODE_RIGHTBRACKET] = KEY_RBRACKET; + scantokey[SDL_SCANCODE_BACKSLASH] = KEY_BACKSLASH; + scantokey[SDL_SCANCODE_SEMICOLON] = KEY_SEMICOLON; + scantokey[SDL_SCANCODE_APOSTROPHE] = KEY_APOSTROPHE; + scantokey[SDL_SCANCODE_GRAVE] = KEY_BACKQUOTE; + scantokey[SDL_SCANCODE_COMMA] = KEY_COMMA; + scantokey[SDL_SCANCODE_PERIOD] = KEY_PERIOD; + scantokey[SDL_SCANCODE_SLASH] = KEY_SLASH; + scantokey[SDL_SCANCODE_CAPSLOCK] = KEY_CAPSLOCK; + scantokey[SDL_SCANCODE_SCROLLLOCK] = KEY_SCROLLLOCK; + scantokey[SDL_SCANCODE_INSERT] = KEY_INSERT; + scantokey[SDL_SCANCODE_HOME] = KEY_HOME; + scantokey[SDL_SCANCODE_PAGEUP] = KEY_PAGEUP; + scantokey[SDL_SCANCODE_DELETE] = KEY_DELETE; + scantokey[SDL_SCANCODE_END] = KEY_END; + scantokey[SDL_SCANCODE_PAGEDOWN] = KEY_PAGEDOWN; + scantokey[SDL_SCANCODE_RIGHT] = KEY_RIGHT; + scantokey[SDL_SCANCODE_LEFT] = KEY_LEFT; + scantokey[SDL_SCANCODE_DOWN] = KEY_DOWN; + scantokey[SDL_SCANCODE_UP] = KEY_UP; + scantokey[SDL_SCANCODE_NUMLOCKCLEAR] = KEY_NUMLOCK; + scantokey[SDL_SCANCODE_KP_DIVIDE] = KEY_PAD_DIVIDE; + scantokey[SDL_SCANCODE_KP_MULTIPLY] = KEY_PAD_MULTIPLY; + scantokey[SDL_SCANCODE_KP_MINUS] = KEY_PAD_MINUS; + scantokey[SDL_SCANCODE_KP_PLUS] = KEY_PAD_PLUS; + // Map keybad enter to enter for vgui. This means vgui dialog won't ever see KEY_PAD_ENTER + scantokey[SDL_SCANCODE_KP_ENTER] = KEY_ENTER; + scantokey[SDL_SCANCODE_KP_PERIOD] = KEY_PAD_DECIMAL; + scantokey[SDL_SCANCODE_APPLICATION] = KEY_APP; + scantokey[SDL_SCANCODE_LCTRL] = KEY_LCONTROL; + scantokey[SDL_SCANCODE_LSHIFT] = KEY_LSHIFT; + scantokey[SDL_SCANCODE_LALT] = KEY_LALT; + scantokey[SDL_SCANCODE_LGUI] = KEY_LWIN; + scantokey[SDL_SCANCODE_RCTRL] = KEY_RCONTROL; + scantokey[SDL_SCANCODE_RSHIFT] = KEY_RSHIFT; + scantokey[SDL_SCANCODE_RALT] = KEY_RALT; + scantokey[SDL_SCANCODE_RGUI] = KEY_RWIN; +} + +bool MapCocoaVirtualKeyToButtonCode( int nCocoaVirtualKeyCode, ButtonCode_t *pOut ) +{ + if ( nCocoaVirtualKeyCode < 0 ) + *pOut = (ButtonCode_t)(-1 * nCocoaVirtualKeyCode); + else + { + nCocoaVirtualKeyCode &= 0x000000ff; + + *pOut = (ButtonCode_t)scantokey[nCocoaVirtualKeyCode]; + } + + return true; +} + +void CInputSystem::PollInputState_Platform() +{ + InputState_t &state = m_InputState[ m_bIsPolling ]; + + if ( m_bPumpEnabled ) + m_pLauncherMgr->PumpWindowsMessageLoop(); + // These are Carbon virtual key codes. AFAIK they don't have a header that defines these, but they are supposed to map + // to the same letters across international keyboards, so our mapping here should work. + CCocoaEvent events[32]; + while ( 1 ) + { + int nEvents = m_pLauncherMgr->GetEvents( events, ARRAYSIZE( events ) ); + if ( nEvents == 0 ) + break; + + for ( int iEvent=0; iEvent < nEvents; iEvent++ ) + { + CCocoaEvent *pEvent = &events[iEvent]; + + switch( pEvent->m_EventType ) + { + case CocoaEvent_Deleted: + break; + + case CocoaEvent_KeyDown: + { + ButtonCode_t virtualCode; + if ( MapCocoaVirtualKeyToButtonCode( pEvent->m_VirtualKeyCode, &virtualCode ) ) + { + ButtonCode_t scanCode = virtualCode; + + if( ( scanCode != BUTTON_CODE_NONE ) ) + { + // For SDL, hitting spacebar causes a SDL_KEYDOWN event, then SDL_TEXTINPUT with + // event.text.text[0] = ' ', and then we get here and wind up sending two events + // to PostButtonPressedEvent. The first is virtualCode = ' ', the 2nd has virtualCode = 0. + // This will confuse Button::OnKeyCodePressed(), which is checking for space keydown + // followed by space keyup. So we ignore all BUTTON_CODE_NONE events here. + PostButtonPressedEvent( IE_ButtonPressed, m_nLastSampleTick, scanCode, virtualCode ); + } + + InputEvent_t event; + memset( &event, 0, sizeof(event) ); + event.m_nTick = GetPollTick(); + // IE_KeyCodeTyped + event.m_nType = IE_FirstVguiEvent + 4; + event.m_nData = scanCode; + g_pInputSystem->PostUserEvent( event ); + + } + + if ( !(pEvent->m_ModifierKeyMask & (1<m_VirtualKeyCode >= 0 && pEvent->m_UnicodeKey > 0 ) + { + InputEvent_t event; + memset( &event, 0, sizeof(event) ); + event.m_nTick = GetPollTick(); + // IE_KeyTyped + event.m_nType = IE_FirstVguiEvent + 3; + event.m_nData = (int)pEvent->m_UnicodeKey; + g_pInputSystem->PostUserEvent( event ); + } + + } + break; + + case CocoaEvent_KeyUp: + { + ButtonCode_t virtualCode; + if ( MapCocoaVirtualKeyToButtonCode( pEvent->m_VirtualKeyCode, &virtualCode ) ) + { + if( virtualCode != BUTTON_CODE_NONE ) + { + ButtonCode_t scanCode = virtualCode; + PostButtonReleasedEvent( IE_ButtonReleased, m_nLastSampleTick, scanCode, virtualCode ); + } + } + } + break; + + case CocoaEvent_MouseButtonDown: + { + int nButtonMask = pEvent->m_MouseButtonFlags; + ButtonCode_t dblClickCode = BUTTON_CODE_INVALID; + if ( pEvent->m_nMouseClickCount > 1 ) + { + switch( pEvent->m_MouseButton ) + { + default: + case COCOABUTTON_LEFT: + dblClickCode = MOUSE_LEFT; + break; + case COCOABUTTON_RIGHT: + dblClickCode = MOUSE_RIGHT; + break; + case COCOABUTTON_MIDDLE: + dblClickCode = MOUSE_MIDDLE; + break; + case COCOABUTTON_4: + dblClickCode = MOUSE_4; + break; + case COCOABUTTON_5: + dblClickCode = MOUSE_5; + break; + } + } + UpdateMouseButtonState( nButtonMask, dblClickCode ); + } + break; + + case CocoaEvent_MouseButtonUp: + { + int nButtonMask = pEvent->m_MouseButtonFlags; + UpdateMouseButtonState( nButtonMask ); + } + break; + + case CocoaEvent_MouseMove: + { + UpdateMousePositionState( state, (short)pEvent->m_MousePos[0], (short)pEvent->m_MousePos[1] ); + + InputEvent_t event; + memset( &event, 0, sizeof(event) ); + event.m_nTick = GetPollTick(); + // IE_LocateMouseClick + event.m_nType = IE_FirstVguiEvent + 1; + event.m_nData = (short)pEvent->m_MousePos[0]; + event.m_nData2 = (short)pEvent->m_MousePos[1]; + g_pInputSystem->PostUserEvent( event ); + } + break; + + case CocoaEvent_MouseScroll: + { + ButtonCode_t code = (short)pEvent->m_MousePos[1] > 0 ? MOUSE_WHEEL_UP : MOUSE_WHEEL_DOWN; + state.m_ButtonPressedTick[ code ] = state.m_ButtonReleasedTick[ code ] = m_nLastSampleTick; + PostEvent( IE_ButtonPressed, m_nLastSampleTick, code, code ); + PostEvent( IE_ButtonReleased, m_nLastSampleTick, code, code ); + + state.m_pAnalogDelta[ MOUSE_WHEEL ] = pEvent->m_MousePos[1]; + state.m_pAnalogValue[ MOUSE_WHEEL ] += state.m_pAnalogDelta[ MOUSE_WHEEL ]; + PostEvent( IE_AnalogValueChanged, m_nLastSampleTick, MOUSE_WHEEL, state.m_pAnalogValue[ MOUSE_WHEEL ], state.m_pAnalogDelta[ MOUSE_WHEEL ] ); + } + break; + + case CocoaEvent_AppActivate: + { + InputEvent_t event; + memset( &event, 0, sizeof(event) ); + event.m_nType = IE_FirstAppEvent + 2; // IE_AppActivated (defined in sys_mainwind.cpp). + event.m_nData = (bool)(pEvent->m_ModifierKeyMask != 0); + + g_pInputSystem->PostUserEvent( event ); + + if( pEvent->m_ModifierKeyMask == 0 ) + { + // App just lost focus. Handle like WM_ACTIVATEAPP in CInputSystem::WindowProc(). + // Otherwise alt+tab will bring focus away from our app, vgui will still think that + // the alt key is down, and when we regain focus, fun ensues. + g_pInputSystem->ResetInputState(); + } + } + break; + case CocoaEvent_AppQuit: + { + PostEvent( IE_Quit, m_nLastSampleTick ); + + } + break; + break; + } + } + } +} +#endif // USE_SDL + + +//----------------------------------------------------------------------------- +// Polls the current input state +//----------------------------------------------------------------------------- +void CInputSystem::PollInputState() +{ + m_bIsPolling = true; + ++m_nPollCount; + + // Deals with polled input events + InputState_t &queuedState = m_InputState[ INPUT_STATE_QUEUED ]; + CopyInputState( &m_InputState[ INPUT_STATE_CURRENT ], queuedState, true ); + + // Sample the joystick + SampleDevices(); + + // NOTE: This happens after SampleDevices since that updates LastSampleTick + // Also, I believe it's correct to post the joystick events with + // the LastPollTick not updated (not 100% sure though) + m_nLastPollTick = m_nLastSampleTick; + +#if defined( PLATFORM_WINDOWS_PC ) + PollInputState_Windows(); +#endif + +#if defined( USE_SDL ) + PollInputState_Platform(); +#endif + + // Leave the queued state up-to-date with the current + CopyInputState( &queuedState, m_InputState[ INPUT_STATE_CURRENT ], false ); + + m_bIsPolling = false; +} + + +//----------------------------------------------------------------------------- +// Computes the sample tick +//----------------------------------------------------------------------------- +int CInputSystem::ComputeSampleTick() +{ + // This logic will only fail if the app has been running for 49.7 days + int nSampleTick; + + DWORD nCurrentTick = Plat_MSTime(); + if ( nCurrentTick >= m_StartupTimeTick ) + { + nSampleTick = (int)( nCurrentTick - m_StartupTimeTick ); + } + else + { + DWORD nDelta = (DWORD)0xFFFFFFFF - m_StartupTimeTick; + nSampleTick = (int)( nCurrentTick + nDelta ) + 1; + } + return nSampleTick; +} + + +//----------------------------------------------------------------------------- +// How many times has poll been called? +//----------------------------------------------------------------------------- +int CInputSystem::GetPollCount() const +{ + return m_nPollCount; +} + +void CInputSystem::PollSteamControllers() +{ +} + +//----------------------------------------------------------------------------- +// Samples attached devices and appends events to the input queue +//----------------------------------------------------------------------------- +void CInputSystem::SampleDevices( void ) +{ + m_nLastSampleTick = ComputeSampleTick(); + + PollJoystick(); + +#if defined( PLATFORM_WINDOWS_PC ) + // NVNT if we have device/s poll them. + if ( m_bNovintDevices ) + { + PollNovintDevices(); + } +#endif + + PollSteamControllers(); +} + +//----------------------------------------------------------------------------- +// Purpose: Sets a player as the primary user - all other controllers will be ignored. +//----------------------------------------------------------------------------- +void CInputSystem::SetPrimaryUserId( int userId ) +{ + if ( userId >= XUSER_MAX_COUNT || userId < 0 ) + { + m_PrimaryUserId = INVALID_USER_ID; + } + else + { + m_PrimaryUserId = userId; + } +#if !defined(POSIX) + XBX_SetPrimaryUserId( m_PrimaryUserId ); +#endif + ConMsg("PrimaryUserId is %d\n", m_PrimaryUserId ); +} + +//----------------------------------------------------------------------------- +// Purpose: Forwards rumble info to attached devices +//----------------------------------------------------------------------------- +void CInputSystem::SetRumble( float fLeftMotor, float fRightMotor, int userId ) +{ + SetXDeviceRumble( fLeftMotor, fRightMotor, userId ); +} + + +//----------------------------------------------------------------------------- +// Purpose: Force an immediate stop, transmits immediately to all devices +//----------------------------------------------------------------------------- +void CInputSystem::StopRumble( void ) +{ +#ifdef _X360 + xdevice_t* pXDevice = &m_XDevices[0]; + + for ( int i = 0; i < XUSER_MAX_COUNT; ++i, ++pXDevice ) + { + if ( pXDevice->active ) + { + pXDevice->vibration.wLeftMotorSpeed = 0; + pXDevice->vibration.wRightMotorSpeed = 0; + pXDevice->pendingRumbleUpdate = true; + WriteToXDevice( pXDevice ); + } + } +#else + for ( int i = 0; i < XUSER_MAX_COUNT; ++i ) + { + SetRumble(0.0, 0.0, i); + } +#endif +} + + +//----------------------------------------------------------------------------- +// Joystick interface +//----------------------------------------------------------------------------- +int CInputSystem::GetJoystickCount() const +{ + return m_nJoystickCount; +} + +void CInputSystem::EnableJoystickInput( int nJoystick, bool bEnable ) +{ + m_JoysticksEnabled.SetFlag( 1 << nJoystick, bEnable ); +} + +void CInputSystem::EnableJoystickDiagonalPOV( int nJoystick, bool bEnable ) +{ + m_pJoystickInfo[ nJoystick ].m_bDiagonalPOVControlEnabled = bEnable; +} + +//----------------------------------------------------------------------------- +// Poll current state +//----------------------------------------------------------------------------- +int CInputSystem::GetPollTick() const +{ + return m_nLastPollTick; +} + +bool CInputSystem::IsButtonDown( ButtonCode_t code ) const +{ + return m_InputState[INPUT_STATE_CURRENT].m_ButtonState.IsBitSet( code ); +} + +int CInputSystem::GetAnalogValue( AnalogCode_t code ) const +{ + return m_InputState[INPUT_STATE_CURRENT].m_pAnalogValue[code]; +} + +int CInputSystem::GetAnalogDelta( AnalogCode_t code ) const +{ + return m_InputState[INPUT_STATE_CURRENT].m_pAnalogDelta[code]; +} + +int CInputSystem::GetButtonPressedTick( ButtonCode_t code ) const +{ + return m_InputState[INPUT_STATE_CURRENT].m_ButtonPressedTick[code]; +} + +int CInputSystem::GetButtonReleasedTick( ButtonCode_t code ) const +{ + return m_InputState[INPUT_STATE_CURRENT].m_ButtonReleasedTick[code]; +} + + +//----------------------------------------------------------------------------- +// Returns the input events since the last poll +//----------------------------------------------------------------------------- +int CInputSystem::GetEventCount() const +{ + return m_InputState[INPUT_STATE_CURRENT].m_Events.Count(); +} + +const InputEvent_t* CInputSystem::GetEventData( ) const +{ + return m_InputState[INPUT_STATE_CURRENT].m_Events.Base(); +} + + +//----------------------------------------------------------------------------- +// Posts a user-defined event into the event queue; this is expected +// to be called in overridden wndprocs connected to the root panel. +//----------------------------------------------------------------------------- +void CInputSystem::PostUserEvent( const InputEvent_t &event ) +{ + InputState_t &state = m_InputState[ m_bIsPolling ]; + state.m_Events.AddToTail( event ); + state.m_bDirty = true; +} + + +//----------------------------------------------------------------------------- +// Chains the window message to the previous wndproc +//----------------------------------------------------------------------------- +inline LRESULT CInputSystem::ChainWindowMessage( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) +{ +#if !defined( POSIX ) + if ( m_ChainedWndProc ) + return CallWindowProc( m_ChainedWndProc, hwnd, uMsg, wParam, lParam ); +#endif + // FIXME: This comment is lifted from vguimatsurface; + // may not apply in future when the system is completed. + + // This means the application is driving the messages (calling our window procedure manually) + // rather than us hooking their window procedure. The engine needs to do this in order for VCR + // mode to play back properly. + return 0; +} + + +//----------------------------------------------------------------------------- +// Release all buttons +//----------------------------------------------------------------------------- +void CInputSystem::ReleaseAllButtons( int nFirstButton, int nLastButton ) +{ + // Force button up messages for all down buttons + for ( int i = nFirstButton; i <= nLastButton; ++i ) + { + PostButtonReleasedEvent( IE_ButtonReleased, m_nLastSampleTick, (ButtonCode_t)i, (ButtonCode_t)i ); + } +} + + +//----------------------------------------------------------------------------- +// Zero analog state +//----------------------------------------------------------------------------- +void CInputSystem::ZeroAnalogState( int nFirstState, int nLastState ) +{ + InputState_t &state = m_InputState[ m_bIsPolling ]; + memset( &state.m_pAnalogDelta[nFirstState], 0, ( nLastState - nFirstState + 1 ) * sizeof(int) ); + memset( &state.m_pAnalogValue[nFirstState], 0, ( nLastState - nFirstState + 1 ) * sizeof(int) ); +} + + +//----------------------------------------------------------------------------- +// Determines all mouse button presses +//----------------------------------------------------------------------------- +int CInputSystem::ButtonMaskFromMouseWParam( WPARAM wParam, ButtonCode_t code, bool bDown ) const +{ + int nButtonMask = 0; + +#if defined( PLATFORM_WINDOWS ) + if ( wParam & MK_LBUTTON ) + { + nButtonMask |= 1; + } + + if ( wParam & MK_RBUTTON ) + { + nButtonMask |= 2; + } + + if ( wParam & MK_MBUTTON ) + { + nButtonMask |= 4; + } + + if ( wParam & MS_MK_BUTTON4 ) + { + nButtonMask |= 8; + } + + if ( wParam & MS_MK_BUTTON5 ) + { + nButtonMask |= 16; + } +#endif + +#ifdef _DEBUG + if ( code != BUTTON_CODE_INVALID ) + { + int nMsgMask = 1 << ( code - MOUSE_FIRST ); + int nTestMask = bDown ? nMsgMask : 0; + Assert( ( nButtonMask & nMsgMask ) == nTestMask ); + } +#endif + + return nButtonMask; +} + + +//----------------------------------------------------------------------------- +// Updates the state of all mouse buttons +//----------------------------------------------------------------------------- +void CInputSystem::UpdateMouseButtonState( int nButtonMask, ButtonCode_t dblClickCode ) +{ + for ( int i = 0; i < 5; ++i ) + { + ButtonCode_t code = (ButtonCode_t)( MOUSE_FIRST + i ); + bool bDown = ( nButtonMask & ( 1 << i ) ) != 0; + if ( bDown ) + { + InputEventType_t type = ( code != dblClickCode ) ? IE_ButtonPressed : IE_ButtonDoubleClicked; + PostButtonPressedEvent( type, m_nLastSampleTick, code, code ); + } + else + { + PostButtonReleasedEvent( IE_ButtonReleased, m_nLastSampleTick, code, code ); + } + } +} + + +//----------------------------------------------------------------------------- +// Handles input messages +//----------------------------------------------------------------------------- +void CInputSystem::SetCursorPosition( int x, int y ) +{ + if ( !m_hAttachedHWnd ) + return; + +#if defined( PLATFORM_WINDOWS ) + POINT pt; + pt.x = x; pt.y = y; + ClientToScreen( (HWND)m_hAttachedHWnd, &pt ); + SetCursorPos( pt.x, pt.y ); +#elif defined( USE_SDL ) + m_pLauncherMgr->SetCursorPosition( x, y ); +#endif + + InputState_t &state = m_InputState[ m_bIsPolling ]; + bool bXChanged = ( state.m_pAnalogValue[ MOUSE_X ] != x ); + bool bYChanged = ( state.m_pAnalogValue[ MOUSE_Y ] != y ); + + state.m_pAnalogValue[ MOUSE_X ] = x; + state.m_pAnalogValue[ MOUSE_Y ] = y; + state.m_pAnalogDelta[ MOUSE_X ] = 0; + state.m_pAnalogDelta[ MOUSE_Y ] = 0; + + if ( bXChanged ) + { + PostEvent( IE_AnalogValueChanged, m_nLastSampleTick, MOUSE_X, state.m_pAnalogValue[ MOUSE_X ], state.m_pAnalogDelta[ MOUSE_X ] ); + } + if ( bYChanged ) + { + PostEvent( IE_AnalogValueChanged, m_nLastSampleTick, MOUSE_Y, state.m_pAnalogValue[ MOUSE_Y ], state.m_pAnalogDelta[ MOUSE_Y ] ); + } + if ( bXChanged || bYChanged ) + { + PostEvent( IE_AnalogValueChanged, m_nLastSampleTick, MOUSE_XY, state.m_pAnalogValue[ MOUSE_X ], state.m_pAnalogValue[ MOUSE_Y ] ); + } +} + + +void CInputSystem::UpdateMousePositionState( InputState_t &state, short x, short y ) +{ + int nOldX = state.m_pAnalogValue[ MOUSE_X ]; + int nOldY = state.m_pAnalogValue[ MOUSE_Y ]; + + state.m_pAnalogValue[ MOUSE_X ] = x; + state.m_pAnalogValue[ MOUSE_Y ] = y; + state.m_pAnalogDelta[ MOUSE_X ] = state.m_pAnalogValue[ MOUSE_X ] - nOldX; + state.m_pAnalogDelta[ MOUSE_Y ] = state.m_pAnalogValue[ MOUSE_Y ] - nOldY; + + if ( state.m_pAnalogDelta[ MOUSE_X ] != 0 ) + { + PostEvent( IE_AnalogValueChanged, m_nLastSampleTick, MOUSE_X, state.m_pAnalogValue[ MOUSE_X ], state.m_pAnalogDelta[ MOUSE_X ] ); + } + if ( state.m_pAnalogDelta[ MOUSE_Y ] != 0 ) + { + PostEvent( IE_AnalogValueChanged, m_nLastSampleTick, MOUSE_Y, state.m_pAnalogValue[ MOUSE_Y ], state.m_pAnalogDelta[ MOUSE_Y ] ); + } + if ( state.m_pAnalogDelta[ MOUSE_X ] != 0 || state.m_pAnalogDelta[ MOUSE_Y ] != 0 ) + { + PostEvent( IE_AnalogValueChanged, m_nLastSampleTick, MOUSE_XY, state.m_pAnalogValue[ MOUSE_X ], state.m_pAnalogValue[ MOUSE_Y ] ); + } +} + +extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); + +//----------------------------------------------------------------------------- +// Handles input messages +//----------------------------------------------------------------------------- +LRESULT CInputSystem::WindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) +{ + /*if*/ (ImGui_ImplWin32_WndProcHandler(hwnd, uMsg, wParam, lParam)); + // return true; + +#if defined( PLATFORM_WINDOWS ) // We use this even for SDL to handle mouse move. + if ( !m_bEnabled ) + return ChainWindowMessage( hwnd, uMsg, wParam, lParam ); + + if ( hwnd != m_hAttachedHWnd ) + return ChainWindowMessage( hwnd, uMsg, wParam, lParam ); + + InputState_t &state = m_InputState[ m_bIsPolling ]; + switch( uMsg ) + { + +#if !defined( USE_SDL ) + case WM_ACTIVATEAPP: + if ( hwnd == m_hAttachedHWnd ) + { + bool bActivated = ( wParam == 1 ); + if ( !bActivated ) + { + ResetInputState(); + } + } + break; + + case WM_LBUTTONDOWN: + { + int nButtonMask = ButtonMaskFromMouseWParam( wParam, MOUSE_LEFT, true ); + ETWMouseDown( 0, (short)LOWORD(lParam), (short)HIWORD(lParam) ); + UpdateMouseButtonState( nButtonMask ); + } + break; + + case WM_LBUTTONUP: + { + int nButtonMask = ButtonMaskFromMouseWParam( wParam, MOUSE_LEFT, false ); + ETWMouseUp( 0, (short)LOWORD(lParam), (short)HIWORD(lParam) ); + UpdateMouseButtonState( nButtonMask ); + } + break; + + case WM_RBUTTONDOWN: + { + int nButtonMask = ButtonMaskFromMouseWParam( wParam, MOUSE_RIGHT, true ); + ETWMouseDown( 2, (short)LOWORD(lParam), (short)HIWORD(lParam) ); + UpdateMouseButtonState( nButtonMask ); + } + break; + + case WM_RBUTTONUP: + { + int nButtonMask = ButtonMaskFromMouseWParam( wParam, MOUSE_RIGHT, false ); + ETWMouseUp( 2, (short)LOWORD(lParam), (short)HIWORD(lParam) ); + UpdateMouseButtonState( nButtonMask ); + } + break; + + case WM_MBUTTONDOWN: + { + int nButtonMask = ButtonMaskFromMouseWParam( wParam, MOUSE_MIDDLE, true ); + ETWMouseDown( 1, (short)LOWORD(lParam), (short)HIWORD(lParam) ); + UpdateMouseButtonState( nButtonMask ); + } + break; + + case WM_MBUTTONUP: + { + int nButtonMask = ButtonMaskFromMouseWParam( wParam, MOUSE_MIDDLE, false ); + ETWMouseUp( 1, (short)LOWORD(lParam), (short)HIWORD(lParam) ); + UpdateMouseButtonState( nButtonMask ); + } + break; + + case MS_WM_XBUTTONDOWN: + { + ButtonCode_t code = ( HIWORD( wParam ) == 1 ) ? MOUSE_4 : MOUSE_5; + int nButtonMask = ButtonMaskFromMouseWParam( wParam, code, true ); + UpdateMouseButtonState( nButtonMask ); + + // Windows docs say the XBUTTON messages we should return true from + return TRUE; + } + break; + + case MS_WM_XBUTTONUP: + { + ButtonCode_t code = ( HIWORD( wParam ) == 1 ) ? MOUSE_4 : MOUSE_5; + int nButtonMask = ButtonMaskFromMouseWParam( wParam, code, false ); + UpdateMouseButtonState( nButtonMask ); + + // Windows docs say the XBUTTON messages we should return true from + return TRUE; + } + break; + + case WM_LBUTTONDBLCLK: + { + int nButtonMask = ButtonMaskFromMouseWParam( wParam, MOUSE_LEFT, true ); + ETWMouseDown( 0, (short)LOWORD(lParam), (short)HIWORD(lParam) ); + UpdateMouseButtonState( nButtonMask, MOUSE_LEFT ); + } + break; + + case WM_RBUTTONDBLCLK: + { + int nButtonMask = ButtonMaskFromMouseWParam( wParam, MOUSE_RIGHT, true ); + ETWMouseDown( 2, (short)LOWORD(lParam), (short)HIWORD(lParam) ); + UpdateMouseButtonState( nButtonMask, MOUSE_RIGHT ); + } + break; + + case WM_MBUTTONDBLCLK: + { + int nButtonMask = ButtonMaskFromMouseWParam( wParam, MOUSE_MIDDLE, true ); + ETWMouseDown( 1, (short)LOWORD(lParam), (short)HIWORD(lParam) ); + UpdateMouseButtonState( nButtonMask, MOUSE_MIDDLE ); + } + break; + + case MS_WM_XBUTTONDBLCLK: + { + ButtonCode_t code = ( HIWORD( wParam ) == 1 ) ? MOUSE_4 : MOUSE_5; + int nButtonMask = ButtonMaskFromMouseWParam( wParam, code, true ); + UpdateMouseButtonState( nButtonMask, code ); + + // Windows docs say the XBUTTON messages we should return true from + return TRUE; + } + break; + + case WM_KEYDOWN: + case WM_SYSKEYDOWN: + { + // Suppress key repeats + if ( !( lParam & ( 1<<30 ) ) ) + { + // NOTE: These two can be unequal! For example, keypad enter + // which returns KEY_ENTER from virtual keys, and KEY_PAD_ENTER from scan codes + // Since things like vgui care about virtual keys; we're going to + // put both scan codes in the input message + ButtonCode_t virtualCode = ButtonCode_VirtualKeyToButtonCode( wParam ); + ButtonCode_t scanCode = ButtonCode_ScanCodeToButtonCode( lParam ); + PostButtonPressedEvent( IE_ButtonPressed, m_nLastSampleTick, scanCode, virtualCode ); + + // Post ETW events describing key presses to help correlate input events to performance + // problems in the game. + ETWKeyDown( scanCode, virtualCode, ButtonCodeToString( virtualCode ) ); + + // Deal with toggles + if ( scanCode == KEY_CAPSLOCK || scanCode == KEY_SCROLLLOCK || scanCode == KEY_NUMLOCK ) + { + int nVirtualKey; + ButtonCode_t toggleCode; + switch( scanCode ) + { + default: case KEY_CAPSLOCK: nVirtualKey = VK_CAPITAL; toggleCode = KEY_CAPSLOCKTOGGLE; break; + case KEY_SCROLLLOCK: nVirtualKey = VK_SCROLL; toggleCode = KEY_SCROLLLOCKTOGGLE; break; + case KEY_NUMLOCK: nVirtualKey = VK_NUMLOCK; toggleCode = KEY_NUMLOCKTOGGLE; break; + }; + + SHORT wState = GetKeyState( nVirtualKey ); + bool bToggleState = ( wState & 0x1 ) != 0; + PostButtonPressedEvent( bToggleState ? IE_ButtonPressed : IE_ButtonReleased, m_nLastSampleTick, toggleCode, toggleCode ); + } + } + } + break; + + case WM_KEYUP: + case WM_SYSKEYUP: + { + // Don't handle key ups if the key's already up. This can happen when we alt-tab back to the engine. + ButtonCode_t virtualCode = ButtonCode_VirtualKeyToButtonCode( wParam ); + ButtonCode_t scanCode = ButtonCode_ScanCodeToButtonCode( lParam ); + PostButtonReleasedEvent( IE_ButtonReleased, m_nLastSampleTick, scanCode, virtualCode ); + } + break; + + case WM_MOUSEWHEEL: + { + ButtonCode_t code = (short)HIWORD( wParam ) > 0 ? MOUSE_WHEEL_UP : MOUSE_WHEEL_DOWN; + state.m_ButtonPressedTick[ code ] = state.m_ButtonReleasedTick[ code ] = m_nLastSampleTick; + PostEvent( IE_ButtonPressed, m_nLastSampleTick, code, code ); + PostEvent( IE_ButtonReleased, m_nLastSampleTick, code, code ); + + state.m_pAnalogDelta[ MOUSE_WHEEL ] = ( (short)HIWORD(wParam) ) / WHEEL_DELTA; + state.m_pAnalogValue[ MOUSE_WHEEL ] += state.m_pAnalogDelta[ MOUSE_WHEEL ]; + PostEvent( IE_AnalogValueChanged, m_nLastSampleTick, MOUSE_WHEEL, state.m_pAnalogValue[ MOUSE_WHEEL ], state.m_pAnalogDelta[ MOUSE_WHEEL ] ); + } + break; + +#if defined( PLATFORM_WINDOWS_PC ) + case WM_INPUT: + { + if ( m_bRawInputSupported ) + { + UINT dwSize = 40; + static BYTE lpb[40]; + + pfnGetRawInputData((HRAWINPUT)lParam, RID_INPUT, lpb, &dwSize, sizeof(RAWINPUTHEADER)); + + RAWINPUT* raw = (RAWINPUT*)lpb; + if (raw->header.dwType == RIM_TYPEMOUSE) + { + m_mouseRawAccumX += raw->data.mouse.lLastX; + m_mouseRawAccumY += raw->data.mouse.lLastY; + } + } + } + break; +#endif + +#endif // !USE_SDL + + case WM_MOUSEMOVE: + { + UpdateMousePositionState( state, (short)LOWORD(lParam), (short)HIWORD(lParam) ); + + int nButtonMask = ButtonMaskFromMouseWParam( wParam ); + UpdateMouseButtonState( nButtonMask ); + } + break; + + } + +#if defined( PLATFORM_WINDOWS_PC ) && !defined( USE_SDL ) + // Can't put this in the case statement, it's not constant + if ( uMsg == m_uiMouseWheel ) + { + ButtonCode_t code = ( ( int )wParam ) > 0 ? MOUSE_WHEEL_UP : MOUSE_WHEEL_DOWN; + state.m_ButtonPressedTick[ code ] = state.m_ButtonReleasedTick[ code ] = m_nLastSampleTick; + PostEvent( IE_ButtonPressed, m_nLastSampleTick, code, code ); + PostEvent( IE_ButtonReleased, m_nLastSampleTick, code, code ); + + state.m_pAnalogDelta[ MOUSE_WHEEL ] = ( ( int )wParam ) / WHEEL_DELTA; + state.m_pAnalogValue[ MOUSE_WHEEL ] += state.m_pAnalogDelta[ MOUSE_WHEEL ]; + PostEvent( IE_AnalogValueChanged, m_nLastSampleTick, MOUSE_WHEEL, state.m_pAnalogValue[ MOUSE_WHEEL ], state.m_pAnalogDelta[ MOUSE_WHEEL ] ); + } +#endif + +#endif // PLATFORM_WINDOWS + return ChainWindowMessage( hwnd, uMsg, wParam, lParam ); +} + +bool CInputSystem::GetRawMouseAccumulators( int& accumX, int& accumY ) +{ +#if defined( USE_SDL ) + + if ( m_pLauncherMgr ) + { + m_pLauncherMgr->GetMouseDelta( accumX, accumY, false ); + return true; + } + return false; + +#else + + accumX = m_mouseRawAccumX; + accumY = m_mouseRawAccumY; + m_mouseRawAccumX = m_mouseRawAccumY = 0; + return m_bRawInputSupported; + +#endif +} + +void CInputSystem::SetConsoleTextMode( bool bConsoleTextMode ) +{ + /* If someone calls this after init, shut it down. */ + if ( bConsoleTextMode && m_bJoystickInitialized ) + { + ShutdownJoysticks(); + } + + m_bConsoleTextMode = bConsoleTextMode; +} + +ISteamController* CInputSystem::SteamControllerInterface() +{ + if ( m_bSkipControllerInitialization ) + { + return nullptr; + } + else + { + return m_SteamAPIContext.SteamController(); + } +} diff --git a/inputsystem/inputsystem.h b/inputsystem/inputsystem.h new file mode 100644 index 0000000..8a25743 --- /dev/null +++ b/inputsystem/inputsystem.h @@ -0,0 +1,471 @@ +//========= 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 +#include +#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" + +#include "../public/steam/isteamcontroller.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 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 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 diff --git a/inputsystem/inputsystem.vpc b/inputsystem/inputsystem.vpc new file mode 100644 index 0000000..ea39f58 --- /dev/null +++ b/inputsystem/inputsystem.vpc @@ -0,0 +1,74 @@ +//----------------------------------------------------------------------------- +// 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 "ImGui" + { + $File "..\thirdparty\imgui\imconfig.h" + $File "..\thirdparty\imgui\imgui.h" + $File "..\thirdparty\imgui\imgui_internal.h" + $File "..\thirdparty\imgui\imstb_rectpack.h" + $File "..\thirdparty\imgui\imstb_textedit.h" + $File "..\thirdparty\imgui\imstb_truetype.h" + $File "..\thirdparty\imgui\imgui_impl_dx9.h" + $File "..\thirdparty\imgui\imgui_impl_win32.h" + + $File "..\thirdparty\imgui\imgui.cpp" + $File "..\thirdparty\imgui\imgui_demo.cpp" + $File "..\thirdparty\imgui\imgui_draw.cpp" + $File "..\thirdparty\imgui\imgui_tables.cpp" + $File "..\thirdparty\imgui\imgui_widgets.cpp" + $File "..\thirdparty\imgui\imgui_impl_dx9.cpp" + $File "..\thirdparty\imgui\imgui_impl_win32.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] + } +} diff --git a/inputsystem/joystick_sdl.cpp b/inputsystem/joystick_sdl.cpp new file mode 100644 index 0000000..86840b1 --- /dev/null +++ b/inputsystem/joystick_sdl.cpp @@ -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; +} diff --git a/inputsystem/key_translation.cpp b/inputsystem/key_translation.cpp new file mode 100644 index 0000000..7f88af0 --- /dev/null +++ b/inputsystem/key_translation.cpp @@ -0,0 +1,911 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//===========================================================================// + + +#if defined( WIN32 ) +#if !defined( _X360 ) +#include +#include +#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(); +} diff --git a/inputsystem/key_translation.h b/inputsystem/key_translation.h new file mode 100644 index 0000000..4552d88 --- /dev/null +++ b/inputsystem/key_translation.h @@ -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 diff --git a/inputsystem/novint.cpp b/inputsystem/novint.cpp new file mode 100644 index 0000000..ee7b1ce --- /dev/null +++ b/inputsystem/novint.cpp @@ -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); + +} \ No newline at end of file diff --git a/inputsystem/posix_stubs.h b/inputsystem/posix_stubs.h new file mode 100644 index 0000000..2178cf7 --- /dev/null +++ b/inputsystem/posix_stubs.h @@ -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 diff --git a/inputsystem/steamcontroller.cpp b/inputsystem/steamcontroller.cpp new file mode 100644 index 0000000..0b3c3b6 --- /dev/null +++ b/inputsystem/steamcontroller.cpp @@ -0,0 +1,698 @@ +//=========== 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 + +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; + } + */ +return 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; iGetConnectedControllers( 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""; + } +} diff --git a/lib/common/SDL2.lib b/lib/common/SDL2.lib new file mode 100644 index 0000000000000000000000000000000000000000..0efa0fd21c3d1fa0a591bf7512d794586246ef68 GIT binary patch literal 168866 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 z%0A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

h1rdzKB3m#VYdi-OAU+rjiowE= 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%0A;Y!$XATjzbeV%x}kTm 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 diff --git a/lib/public/SDL2.lib b/lib/public/SDL2.lib new file mode 100644 index 0000000000000000000000000000000000000000..0efa0fd21c3d1fa0a591bf7512d794586246ef68 GIT binary patch literal 168866 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