Merge pull request #8395 from Robyt3/Client-Input-Event-Refactoring

Refactor client input event handling
This commit is contained in:
Dennis Felsing 2024-06-05 05:26:23 +00:00 committed by GitHub
commit 5eda5e9fe3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 101 additions and 103 deletions

View file

@ -33,19 +33,25 @@
// for platform specific features that aren't available or are broken in SDL
#include <SDL_syswm.h>
void CInput::AddEvent(char *pText, int Key, int Flags)
void CInput::AddKeyEvent(int Key, int Flags)
{
if(m_NumEvents != INPUT_BUFFER_SIZE)
{
m_aInputEvents[m_NumEvents].m_Key = Key;
m_aInputEvents[m_NumEvents].m_Flags = Flags;
if(pText == nullptr)
m_aInputEvents[m_NumEvents].m_aText[0] = '\0';
else
str_copy(m_aInputEvents[m_NumEvents].m_aText, pText);
m_aInputEvents[m_NumEvents].m_InputCount = m_InputCounter;
m_NumEvents++;
dbg_assert((Flags & (FLAG_PRESS | FLAG_RELEASE)) != 0 && (Flags & ~(FLAG_PRESS | FLAG_RELEASE)) == 0, "Flags invalid");
CEvent Event;
Event.m_Key = Key;
Event.m_Flags = Flags;
Event.m_aText[0] = '\0';
Event.m_InputCount = m_InputCounter;
m_vInputEvents.emplace_back(Event);
}
void CInput::AddTextEvent(const char *pText)
{
CEvent Event;
Event.m_Key = KEY_UNKNOWN;
Event.m_Flags = FLAG_TEXT;
str_copy(Event.m_aText, pText);
Event.m_InputCount = m_InputCounter;
m_vInputEvents.emplace_back(Event);
}
CInput::CInput()
@ -53,6 +59,7 @@ CInput::CInput()
mem_zero(m_aInputCount, sizeof(m_aInputCount));
mem_zero(m_aInputState, sizeof(m_aInputState));
m_vInputEvents.reserve(32);
m_LastUpdate = 0;
m_UpdateTime = 0.0f;
@ -60,8 +67,6 @@ CInput::CInput()
m_InputGrabbed = false;
m_MouseDoubleClick = false;
m_NumEvents = 0;
m_MouseFocus = true;
m_pClipboardText = nullptr;
@ -342,11 +347,29 @@ void CInput::StopTextInput()
m_vCandidates.clear();
}
void CInput::ConsumeEvents(std::function<void(const CEvent &Event)> Consumer) const
{
for(const CEvent &Event : m_vInputEvents)
{
// Only propagate valid input events
if(Event.m_InputCount == m_InputCounter)
{
Consumer(Event);
}
}
}
void CInput::Clear()
{
mem_zero(m_aInputState, sizeof(m_aInputState));
mem_zero(m_aInputCount, sizeof(m_aInputCount));
m_NumEvents = 0;
m_vInputEvents.clear();
m_MouseDoubleClick = false;
}
float CInput::GetUpdateTime() const
{
return m_UpdateTime;
}
bool CInput::KeyState(int Key) const
@ -424,24 +447,24 @@ void CInput::HandleJoystickAxisMotionEvent(const SDL_JoyAxisEvent &Event)
{
m_aInputState[LeftKey] = true;
m_aInputCount[LeftKey] = m_InputCounter;
AddEvent(nullptr, LeftKey, IInput::FLAG_PRESS);
AddKeyEvent(LeftKey, IInput::FLAG_PRESS);
}
else if(Event.value > SDL_JOYSTICK_AXIS_MIN * DeadZone && m_aInputState[LeftKey])
{
m_aInputState[LeftKey] = false;
AddEvent(nullptr, LeftKey, IInput::FLAG_RELEASE);
AddKeyEvent(LeftKey, IInput::FLAG_RELEASE);
}
if(Event.value >= SDL_JOYSTICK_AXIS_MAX * DeadZone && !m_aInputState[RightKey])
{
m_aInputState[RightKey] = true;
m_aInputCount[RightKey] = m_InputCounter;
AddEvent(nullptr, RightKey, IInput::FLAG_PRESS);
AddKeyEvent(RightKey, IInput::FLAG_PRESS);
}
else if(Event.value < SDL_JOYSTICK_AXIS_MAX * DeadZone && m_aInputState[RightKey])
{
m_aInputState[RightKey] = false;
AddEvent(nullptr, RightKey, IInput::FLAG_RELEASE);
AddKeyEvent(RightKey, IInput::FLAG_RELEASE);
}
}
@ -461,12 +484,12 @@ void CInput::HandleJoystickButtonEvent(const SDL_JoyButtonEvent &Event)
{
m_aInputState[Key] = true;
m_aInputCount[Key] = m_InputCounter;
AddEvent(nullptr, Key, IInput::FLAG_PRESS);
AddKeyEvent(Key, IInput::FLAG_PRESS);
}
else if(Event.type == SDL_JOYBUTTONUP)
{
m_aInputState[Key] = false;
AddEvent(nullptr, Key, IInput::FLAG_RELEASE);
AddKeyEvent(Key, IInput::FLAG_RELEASE);
}
}
@ -488,7 +511,7 @@ void CInput::HandleJoystickHatMotionEvent(const SDL_JoyHatEvent &Event)
if(Key != HatKeys[0] && Key != HatKeys[1] && m_aInputState[Key])
{
m_aInputState[Key] = false;
AddEvent(nullptr, Key, IInput::FLAG_RELEASE);
AddKeyEvent(Key, IInput::FLAG_RELEASE);
}
}
@ -498,7 +521,7 @@ void CInput::HandleJoystickHatMotionEvent(const SDL_JoyHatEvent &Event)
{
m_aInputState[CurrentKey] = true;
m_aInputCount[CurrentKey] = m_InputCounter;
AddEvent(nullptr, CurrentKey, IInput::FLAG_PRESS);
AddKeyEvent(CurrentKey, IInput::FLAG_PRESS);
}
}
}
@ -582,8 +605,8 @@ int CInput::Update()
}
m_LastUpdate = Now;
// keep the counter between 1..0xFFFF, 0 means not pressed
m_InputCounter = (m_InputCounter % 0xFFFF) + 1;
// keep the counter between 1..0xFFFFFFFF, 0 means not pressed
m_InputCounter = (m_InputCounter % std::numeric_limits<decltype(m_InputCounter)>::max()) + 1;
// Ensure that we have the latest keyboard, mouse and joystick state
SDL_PumpEvents();
@ -621,7 +644,7 @@ int CInput::Update()
for(int i = 0; i < Event.edit.start; i++)
m_CompositionCursor = str_utf8_forward(m_aComposition, m_CompositionCursor);
// Event.edit.length is currently unused on Windows and will always be 0, so we don't support selecting composition text
AddEvent(nullptr, KEY_UNKNOWN, IInput::FLAG_TEXT);
AddTextEvent("");
}
else
{
@ -636,7 +659,7 @@ int CInput::Update()
m_aComposition[0] = '\0';
m_CompositionLength = COMP_LENGTH_INACTIVE;
m_CompositionCursor = 0;
AddEvent(Event.text.text, KEY_UNKNOWN, IInput::FLAG_TEXT);
AddTextEvent(Event.text.text);
break;
// handle keys
@ -806,7 +829,7 @@ int CInput::Update()
m_aInputState[Scancode] = 1;
m_aInputCount[Scancode] = m_InputCounter;
}
AddEvent(nullptr, Scancode, Action);
AddKeyEvent(Scancode, Action);
}
}

View file

@ -92,14 +92,17 @@ private:
std::vector<std::string> m_vCandidates;
int m_CandidateSelectedIndex;
void AddEvent(char *pText, int Key, int Flags);
void Clear() override;
bool IsEventValid(const CEvent &Event) const override { return Event.m_InputCount == m_InputCounter; }
// events
std::vector<CEvent> m_vInputEvents;
int64_t m_LastUpdate;
float m_UpdateTime;
void AddKeyEvent(int Key, int Flags);
void AddTextEvent(const char *pText);
// quick access to input
unsigned short m_aInputCount[g_MaxKeys]; // tw-KEY
unsigned char m_aInputState[g_MaxKeys]; // SDL_SCANCODE
int m_InputCounter;
uint32_t m_aInputCount[g_MaxKeys];
unsigned char m_aInputState[g_MaxKeys];
uint32_t m_InputCounter;
void UpdateMouseState();
void UpdateJoystickState();
@ -122,6 +125,10 @@ public:
int Update() override;
void Shutdown() override;
void ConsumeEvents(std::function<void(const CEvent &Event)> Consumer) const override;
void Clear() override;
float GetUpdateTime() const override;
bool ModifierIsPressed() const override { return KeyState(KEY_LCTRL) || KeyState(KEY_RCTRL) || KeyState(KEY_LGUI) || KeyState(KEY_RGUI); }
bool ShiftIsPressed() const override { return KeyState(KEY_LSHIFT) || KeyState(KEY_RSHIFT); }
bool AltIsPressed() const override { return KeyState(KEY_LALT) || KeyState(KEY_RALT); }

View file

@ -4,7 +4,11 @@
#define ENGINE_INPUT_H
#include "kernel.h"
#include <base/system.h>
#include <base/types.h>
#include <cstdint>
#include <functional>
const int g_MaxKeys = 512;
extern const char g_aaKeyStrings[g_MaxKeys][20];
@ -23,23 +27,10 @@ public:
public:
int m_Flags;
int m_Key;
uint32_t m_InputCount;
char m_aText[INPUT_TEXT_SIZE];
int m_InputCount;
};
protected:
enum
{
INPUT_BUFFER_SIZE = 32
};
// quick access to events
size_t m_NumEvents;
CEvent m_aInputEvents[INPUT_BUFFER_SIZE];
int64_t m_LastUpdate;
float m_UpdateTime;
public:
enum
{
FLAG_PRESS = 1 << 0,
@ -60,19 +51,14 @@ public:
};
// events
size_t NumEvents() const { return m_NumEvents; }
virtual bool IsEventValid(const CEvent &Event) const = 0;
const CEvent &GetEvent(size_t Index) const
{
dbg_assert(Index < m_NumEvents, "Index invalid");
return m_aInputEvents[Index];
}
virtual void ConsumeEvents(std::function<void(const CEvent &Event)> Consumer) const = 0;
virtual void Clear() = 0;
/**
* @return Rolling average of the time in seconds between
* calls of the Update function.
*/
float GetUpdateTime() const { return m_UpdateTime; }
virtual float GetUpdateTime() const = 0;
// keys
virtual bool ModifierIsPressed() const = 0;
@ -81,7 +67,6 @@ public:
virtual bool KeyIsPressed(int Key) const = 0;
virtual bool KeyPress(int Key, bool CheckCounter = false) const = 0;
const char *KeyName(int Key) const { return (Key >= 0 && Key < g_MaxKeys) ? g_aaKeyStrings[Key] : g_aaKeyStrings[0]; }
virtual void Clear() = 0;
// joystick
class IJoystick

View file

@ -2,6 +2,8 @@
#include "gameclient.h"
#include <base/system.h>
class IKernel *CComponent::Kernel() const { return m_pClient->Kernel(); }
class IEngine *CComponent::Engine() const { return m_pClient->Engine(); }
class IGraphics *CComponent::Graphics() const { return m_pClient->Graphics(); }
@ -27,6 +29,15 @@ class IUpdater *CComponent::Updater() const
}
#endif
int64_t CComponent::time() const
{
#if defined(CONF_VIDEORECORDER)
return IVideo::Current() ? IVideo::Time() : time_get();
#else
return time_get();
#endif
}
float CComponent::LocalTime() const
{
#if defined(CONF_VIDEORECORDER)

View file

@ -104,25 +104,12 @@ protected:
class IUpdater *Updater() const;
#endif
#if defined(CONF_VIDEORECORDER)
/**
* Gets the current time.
* @see time_get()
*/
int64_t time() const
{
return IVideo::Current() ? IVideo::Time() : time_get();
}
#else
/**
* Gets the current time.
* @see time_get()
*/
int64_t time() const
{
return time_get();
}
#endif
int64_t time() const;
/**
* Gets the local time.
*/

View file

@ -2,6 +2,8 @@
/* If you are missing that file, acquire a complete release at teeworlds.com. */
#include "voting.h"
#include <base/system.h>
#include <engine/shared/config.h>
#include <engine/textrender.h>
@ -139,6 +141,11 @@ void CVoting::Vote(int v)
Client()->SendPackMsgActive(&Msg, MSGFLAG_VITAL);
}
int CVoting::SecondsLeft() const
{
return (m_Closetime - time()) / time_freq();
}
CVoting::CVoting()
{
ClearOptions();

View file

@ -57,8 +57,8 @@ public:
void Vote(int v); // -1 = no, 1 = yes
int SecondsLeft() { return (m_Closetime - time()) / time_freq(); }
bool IsVoting() { return m_Closetime != 0; }
int SecondsLeft() const;
bool IsVoting() const { return m_Closetime != 0; }
int TakenChoice() const { return m_Voted; }
const char *VoteDescription() const { return m_aDescription; }
const char *VoteReason() const { return m_aReason; }

View file

@ -385,18 +385,13 @@ void CGameClient::OnUpdate()
}
// handle key presses
for(size_t i = 0; i < Input()->NumEvents(); i++)
{
const IInput::CEvent &Event = Input()->GetEvent(i);
if(!Input()->IsEventValid(Event))
continue;
Input()->ConsumeEvents([&](const IInput::CEvent &Event) {
for(auto &pComponent : m_vpInput)
{
if(pComponent->OnInput(Event))
break;
}
}
});
if(g_Config.m_ClSubTickAiming && m_Binds.m_MouseOnAction)
{

View file

@ -8482,17 +8482,6 @@ void CEditor::OnMouseMove(float MouseX, float MouseY)
Ui()->MapScreen();
}
void CEditor::DispatchInputEvents()
{
for(size_t i = 0; i < Input()->NumEvents(); i++)
{
const IInput::CEvent &Event = Input()->GetEvent(i);
if(!Input()->IsEventValid(Event))
continue;
Ui()->OnInput(Event);
}
}
void CEditor::HandleAutosave()
{
const float Time = Client()->GlobalTime();
@ -8624,21 +8613,16 @@ void CEditor::OnUpdate()
m_pContainerPannedLast = m_pContainerPanned;
// handle key presses
for(size_t i = 0; i < Input()->NumEvents(); i++)
{
const IInput::CEvent &Event = Input()->GetEvent(i);
if(!Input()->IsEventValid(Event))
continue;
Input()->ConsumeEvents([&](const IInput::CEvent &Event) {
for(CEditorComponent &Component : m_vComponents)
{
if(Component.OnInput(Event))
break;
}
return;
}
Ui()->OnInput(Event);
});
HandleCursorMovement();
DispatchInputEvents();
HandleAutosave();
HandleWriterFinishJobs();

View file

@ -465,7 +465,6 @@ public:
void HandleCursorMovement();
void OnMouseMove(float MouseX, float MouseY);
void DispatchInputEvents();
void HandleAutosave();
bool PerformAutosave();
void HandleWriterFinishJobs();