mirror of
https://github.com/ddnet/ddnet.git
synced 2024-11-19 14:38:18 +00:00
Merge pull request #8395 from Robyt3/Client-Input-Event-Refactoring
Refactor client input event handling
This commit is contained in:
commit
5eda5e9fe3
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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); }
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -465,7 +465,6 @@ public:
|
|||
|
||||
void HandleCursorMovement();
|
||||
void OnMouseMove(float MouseX, float MouseY);
|
||||
void DispatchInputEvents();
|
||||
void HandleAutosave();
|
||||
bool PerformAutosave();
|
||||
void HandleWriterFinishJobs();
|
||||
|
|
Loading…
Reference in a new issue