From 4f1092829955a73d462193163f774b614234c1a6 Mon Sep 17 00:00:00 2001 From: nillerusr Date: Thu, 17 Aug 2023 14:31:43 +0300 Subject: [PATCH] inputsystem: fix UB in touch events callback, make touch more responsive --- engine/sys_mainwind.cpp | 2 +- game/client/cdll_client_int.cpp | 20 ++++++--------- inputsystem/inputsystem.cpp | 10 -------- inputsystem/inputsystem.h | 7 +++--- inputsystem/touch_sdl.cpp | 42 ++++++++++++++++++++++--------- public/cdll_int.h | 2 +- public/inputsystem/iinputsystem.h | 1 + vguimatsurface/Input.cpp | 23 +++++++++-------- 8 files changed, 58 insertions(+), 49 deletions(-) diff --git a/engine/sys_mainwind.cpp b/engine/sys_mainwind.cpp index 6003bf7c..8cbb3fdc 100644 --- a/engine/sys_mainwind.cpp +++ b/engine/sys_mainwind.cpp @@ -355,7 +355,7 @@ void CGame::HandleMsg_Close( const InputEvent_t &event ) void CGame::DispatchInputEvent( const InputEvent_t &event ) { - switch( event.m_nType & 0xFFFF ) + switch( event.m_nType ) { // Handle button events specially, // since we have all manner of crazy filtering going on when dealing with them diff --git a/game/client/cdll_client_int.cpp b/game/client/cdll_client_int.cpp index 1bbfae96..e4221104 100644 --- a/game/client/cdll_client_int.cpp +++ b/game/client/cdll_client_int.cpp @@ -729,7 +729,7 @@ public: void PrecacheMaterial( const char *pMaterialName ); virtual bool IsConnectedUserInfoChangeAllowed( IConVar *pCvar ); - virtual void IN_TouchEvent( uint data, uint data2, uint data3, uint data4 ); + virtual void IN_TouchEvent( int type, int fingerId, int x, int y ); private: void UncacheAllMaterials( ); @@ -2637,24 +2637,20 @@ CSteamID GetSteamIDForPlayerIndex( int iPlayerIndex ) #endif -void CHLClient::IN_TouchEvent( uint data, uint data2, uint data3, uint data4 ) +void CHLClient::IN_TouchEvent( int type, int fingerId, int x, int y ) { if( enginevgui->IsGameUIVisible() ) return; touch_event_t ev; - ev.type = data & 0xFFFF; - ev.fingerid = (data >> 16) & 0xFFFF; - ev.x = (double)((data2 >> 16) & 0xFFFF) / 0xFFFF; - ev.y = (double)(data2 & 0xFFFF) / 0xFFFF; + ev.type = type; + ev.fingerid = fingerId; + memcpy( &ev.x, &x, sizeof(ev.x) ); + memcpy( &ev.y, &y, sizeof(ev.y) ); - union{uint i;float f;} ifconv; - ifconv.i = data3; - ev.dx = ifconv.f; - - ifconv.i = data4; - ev.dy = ifconv.f; + if( type == IE_FingerMotion ) + inputsystem->GetTouchAccumulators( fingerId, ev.dx, ev.dy ); gTouch.ProcessEvent( &ev ); } diff --git a/inputsystem/inputsystem.cpp b/inputsystem/inputsystem.cpp index 44a0c785..6ec446d9 100644 --- a/inputsystem/inputsystem.cpp +++ b/inputsystem/inputsystem.cpp @@ -1530,16 +1530,6 @@ bool CInputSystem::GetRawMouseAccumulators( int& accumX, int& accumY ) #endif } -bool CInputSystem::GetTouchAccumulators( InputEventType_t &event, int &fingerId, int& accumX, int& accumY ) -{ - event = m_touchAccumEvent; - fingerId = m_touchAccumFingerId; - accumX = m_touchAccumX; - accumY = m_touchAccumY; - - return m_bJoystickInitialized; -} - void CInputSystem::SetConsoleTextMode( bool bConsoleTextMode ) { /* If someone calls this after init, shut it down. */ diff --git a/inputsystem/inputsystem.h b/inputsystem/inputsystem.h index c369851e..8038a1ff 100644 --- a/inputsystem/inputsystem.h +++ b/inputsystem/inputsystem.h @@ -44,6 +44,8 @@ #include "steam/steam_api.h" +#define TOUCH_FINGER_MAX_COUNT 10 + //----------------------------------------------------------------------------- // Implementation of the input system //----------------------------------------------------------------------------- @@ -101,7 +103,7 @@ public: virtual void *GetHapticsInterfaceAddress() const { return NULL;} #endif bool GetRawMouseAccumulators( int& accumX, int& accumY ); - bool GetTouchAccumulators( InputEventType_t &event, int &fingerId, int& accumX, int& accumY ); + virtual bool GetTouchAccumulators( int fingerId, float &dx, float &dy ); virtual void SetConsoleTextMode( bool bConsoleTextMode ); @@ -458,8 +460,7 @@ public: bool m_bRawInputSupported; int m_mouseRawAccumX, m_mouseRawAccumY; - InputEventType_t m_touchAccumEvent; - int m_touchAccumFingerId, m_touchAccumX, m_touchAccumY; + float m_touchAccumX[TOUCH_FINGER_MAX_COUNT], m_touchAccumY[TOUCH_FINGER_MAX_COUNT]; // For the 'SleepUntilInput' feature HANDLE m_hEvent; diff --git a/inputsystem/touch_sdl.cpp b/inputsystem/touch_sdl.cpp index 5e7cf2cf..5eb80844 100644 --- a/inputsystem/touch_sdl.cpp +++ b/inputsystem/touch_sdl.cpp @@ -48,6 +48,9 @@ void CInputSystem::InitializeTouch( void ) // abort startup if user requests no touch if ( CommandLine()->FindParm("-notouch") ) return; + memset( m_touchAccumX, 0, sizeof(m_touchAccumX) ); + memset( m_touchAccumY, 0, sizeof(m_touchAccumY) ); + m_bJoystickInitialized = true; SDL_AddEventWatch(TouchSDLWatcher, this); } @@ -61,20 +64,35 @@ void CInputSystem::ShutdownTouch() m_bTouchInitialized = false; } -void CInputSystem::FingerEvent(int eventType, int fingerId, float x, float y, float dx, float dy) +bool CInputSystem::GetTouchAccumulators( int fingerId, float &dx, float &dy ) { - // Shit, but should work with arm/x86 + dx = m_touchAccumX[fingerId]; + dy = m_touchAccumY[fingerId]; - int data0 = fingerId << 16 | eventType; - int _x = (int)((double)x*0xFFFF); - int _y = (int)((double)y*0xFFFF); - int data1 = _x << 16 | (_y & 0xFFFF); + m_touchAccumX[fingerId] = m_touchAccumY[fingerId] = 0.f; - union{int i;float f;} ifconv; - ifconv.f = dx; - int _dx = ifconv.i; - ifconv.f = dy; - int _dy = ifconv.i; + return true; +} - PostEvent(data0, m_nLastSampleTick, data1, _dx, _dy); +void CInputSystem::FingerEvent(int eventType, int fingerId, float x, float y, float dx, float dy) +{ + if( fingerId >= TOUCH_FINGER_MAX_COUNT ) + return; + + if( eventType == IE_FingerUp ) + { + m_touchAccumX[fingerId] = 0.f; + m_touchAccumY[fingerId] = 0.f; + } + else + { + m_touchAccumX[fingerId] += dx; + m_touchAccumY[fingerId] += dy; + } + + int _x,_y; + memcpy( &_x, &x, sizeof(float) ); + memcpy( &_y, &y, sizeof(float) ); + PostEvent(eventType, m_nLastSampleTick, fingerId, _x, _y); } + diff --git a/public/cdll_int.h b/public/cdll_int.h index 85cd7617..d3e6dc44 100644 --- a/public/cdll_int.h +++ b/public/cdll_int.h @@ -790,7 +790,7 @@ public: virtual bool IsConnectedUserInfoChangeAllowed( IConVar *pCvar ) = 0; - virtual void IN_TouchEvent( uint data, uint data2, uint data3, uint data4 ) = 0; + virtual void IN_TouchEvent( int type, int fingerId, int x, int y ) = 0; }; #define CLIENT_DLL_INTERFACE_VERSION "VClient017" diff --git a/public/inputsystem/iinputsystem.h b/public/inputsystem/iinputsystem.h index 07bc2fe9..6135a88d 100644 --- a/public/inputsystem/iinputsystem.h +++ b/public/inputsystem/iinputsystem.h @@ -119,6 +119,7 @@ public: // read and clear accumulated raw input values virtual bool GetRawMouseAccumulators( int& accumX, int& accumY ) = 0; + virtual bool GetTouchAccumulators( int fingerId, float &dx, float &dy ) = 0; // tell the input system that we're not a game, we're console text mode. // this is used for dedicated servers to not initialize joystick system. diff --git a/vguimatsurface/Input.cpp b/vguimatsurface/Input.cpp index 744aafbb..85836e00 100644 --- a/vguimatsurface/Input.cpp +++ b/vguimatsurface/Input.cpp @@ -376,7 +376,7 @@ static vgui::MouseCode ButtonCodeToMouseCode( ButtonCode_t buttonCode ) //----------------------------------------------------------------------------- bool InputHandleInputEvent( const InputEvent_t &event ) { - switch( event.m_nType & 0xFFFF ) + switch( event.m_nType ) { case IE_ButtonPressed: { @@ -428,9 +428,10 @@ bool InputHandleInputEvent( const InputEvent_t &event ) case IE_FingerDown: { int w,h,x,y; g_MatSystemSurface.GetScreenSize(w, h); - uint data = (uint)event.m_nData; - x = w*((double)((data >> 16) & 0xFFFF) / 0xFFFF); - y = h*((double)(data & 0xFFFF) / 0xFFFF); + float _x, _y; + memcpy( &_x, &event.m_nData2, sizeof(_x) ); + memcpy( &_y, &event.m_nData3, sizeof(_y) ); + x = w*_x; y = h*_y; g_pIInput->UpdateCursorPosInternal( x, y ); g_pIInput->SetMouseCodeState( MOUSE_LEFT, vgui::BUTTON_PRESSED ); g_pIInput->InternalMousePressed( MOUSE_LEFT ); @@ -439,9 +440,10 @@ bool InputHandleInputEvent( const InputEvent_t &event ) case IE_FingerUp: { int w,h,x,y; g_MatSystemSurface.GetScreenSize(w, h); - uint data = (uint)event.m_nData; - x = w*((double)((data >> 16) & 0xFFFF) / 0xFFFF); - y = h*((double)(data & 0xFFFF) / 0xFFFF); + float _x, _y; + memcpy( &_x, &event.m_nData2, sizeof(_x) ); + memcpy( &_y, &event.m_nData3, sizeof(_y) ); + x = w*_x; y = h*_y; g_pIInput->UpdateCursorPosInternal( x, y ); g_pIInput->SetMouseCodeState( MOUSE_LEFT, vgui::BUTTON_RELEASED ); g_pIInput->InternalMouseReleased( MOUSE_LEFT ); @@ -450,9 +452,10 @@ bool InputHandleInputEvent( const InputEvent_t &event ) case IE_FingerMotion: { int w,h,x,y; g_MatSystemSurface.GetScreenSize(w, h); - uint data = (uint)event.m_nData; - x = w*((double)((data >> 16) & 0xFFFF) / 0xFFFF); - y = h*((double)(data & 0xFFFF) / 0xFFFF); + float _x, _y; + memcpy( &_x, &event.m_nData2, sizeof(_x) ); + memcpy( &_y, &event.m_nData3, sizeof(_y) ); + x = w*_x; y = h*_y; g_pIInput->InternalCursorMoved( x, y ); } return true;