diff --git a/src/engine/client/input.cpp b/src/engine/client/input.cpp index bf8bb179a..63931295a 100644 --- a/src/engine/client/input.cpp +++ b/src/engine/client/input.cpp @@ -33,19 +33,25 @@ // for platform specific features that aren't available or are broken in SDL #include -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 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::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); } } diff --git a/src/engine/client/input.h b/src/engine/client/input.h index 00fd15c8e..7cef8f816 100644 --- a/src/engine/client/input.h +++ b/src/engine/client/input.h @@ -92,14 +92,17 @@ private: std::vector 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 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 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); } diff --git a/src/engine/input.h b/src/engine/input.h index 87740c2fa..d1d926604 100644 --- a/src/engine/input.h +++ b/src/engine/input.h @@ -4,7 +4,11 @@ #define ENGINE_INPUT_H #include "kernel.h" -#include + +#include + +#include +#include 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 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 diff --git a/src/game/client/component.cpp b/src/game/client/component.cpp index 0d085f428..c682d7457 100644 --- a/src/game/client/component.cpp +++ b/src/game/client/component.cpp @@ -2,6 +2,8 @@ #include "gameclient.h" +#include + 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) diff --git a/src/game/client/component.h b/src/game/client/component.h index be49eb991..639c8b140 100644 --- a/src/game/client/component.h +++ b/src/game/client/component.h @@ -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. */ diff --git a/src/game/client/components/voting.cpp b/src/game/client/components/voting.cpp index f25dedf99..0c2fbb57e 100644 --- a/src/game/client/components/voting.cpp +++ b/src/game/client/components/voting.cpp @@ -2,6 +2,8 @@ /* If you are missing that file, acquire a complete release at teeworlds.com. */ #include "voting.h" +#include + #include #include @@ -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(); diff --git a/src/game/client/components/voting.h b/src/game/client/components/voting.h index 3e5531a6a..2d3d36d15 100644 --- a/src/game/client/components/voting.h +++ b/src/game/client/components/voting.h @@ -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; } diff --git a/src/game/client/gameclient.cpp b/src/game/client/gameclient.cpp index 64164b41d..cedf92971 100644 --- a/src/game/client/gameclient.cpp +++ b/src/game/client/gameclient.cpp @@ -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) { diff --git a/src/game/editor/editor.cpp b/src/game/editor/editor.cpp index 767c8a6f7..f14cf5d72 100644 --- a/src/game/editor/editor.cpp +++ b/src/game/editor/editor.cpp @@ -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(); diff --git a/src/game/editor/editor.h b/src/game/editor/editor.h index 0801c1f04..e9172ebb0 100644 --- a/src/game/editor/editor.h +++ b/src/game/editor/editor.h @@ -465,7 +465,6 @@ public: void HandleCursorMovement(); void OnMouseMove(float MouseX, float MouseY); - void DispatchInputEvents(); void HandleAutosave(); bool PerformAutosave(); void HandleWriterFinishJobs();