osb/source/game/StarInput.hpp

215 lines
5.6 KiB
C++
Raw Normal View History

2023-07-01 20:34:43 +00:00
#ifndef STAR_INPUT_HPP
#define STAR_INPUT_HPP
#include "StarInputEvent.hpp"
#include "StarJson.hpp"
#include "StarListener.hpp"
#include "StarHash.hpp"
namespace Star {
STAR_CLASS(Input);
STAR_EXCEPTION(InputException, StarException);
2023-07-01 20:34:43 +00:00
typedef Variant<Key, MouseButton, ControllerButton> InputVariant;
2023-07-01 20:34:43 +00:00
template <>
struct hash<InputVariant> {
size_t operator()(InputVariant const& v) const;
};
class Input {
public:
static Json inputEventToJson(InputEvent const& event);
struct KeyBind {
Key key = Key::Zero;
KeyMod mods = KeyMod::NoMod;
uint8_t priority = 0;
inline bool operator<(KeyBind const& rhs) const {
return priority < rhs.priority;
}
inline bool operator>(KeyBind const& rhs) const {
return priority > rhs.priority;
}
2023-07-01 20:34:43 +00:00
};
struct MouseBind {
MouseButton button = MouseButton::Left;
KeyMod mods = KeyMod::NoMod;
uint8_t priority = 0;
};
2023-07-02 00:55:25 +00:00
struct ControllerBind {
unsigned int controller = 0;
ControllerButton button = ControllerButton::Invalid;
};
2023-07-02 00:55:25 +00:00
typedef MVariant<KeyBind, MouseBind, ControllerBind> Bind;
2023-07-01 20:34:43 +00:00
static Bind bindFromJson(Json const& json);
static Json bindToJson(Bind const& bind);
2023-07-01 20:34:43 +00:00
struct BindCategory;
2023-07-01 20:34:43 +00:00
struct BindEntry {
// The internal ID of this entry.
String id;
// The user-facing name of this entry.
String name;
// The category this entry belongs to.
BindCategory const* category;
// The default binds.
List<Bind> defaultBinds;
// The user-configured binds.
List<Bind> customBinds;
BindEntry(String entryId, Json const& config, BindCategory const& parentCategory);
void updated();
};
struct BindRef {
KeyMod mods;
uint8_t priority = 0;
BindEntry* entry = nullptr; // Invalidated on reload, careful!
BindRef(BindEntry& bindEntry, KeyBind& keyBind);
BindRef(BindEntry& bindEntry, MouseBind& mouseBind);
BindRef(BindEntry& bindEntry);
};
struct BindCategory {
String id;
String name;
Json config;
StableHashMap<String, BindEntry> entries;
BindCategory(String categoryId, Json const& categoryConfig);
};
struct InputState {
unsigned presses = 0;
unsigned releases = 0;
bool pressed = false;
bool held = false;
bool released = false;
// Calls the passed functions for each press and release.
template <typename PressFunction, typename ReleaseFunction>
void forEach(PressFunction&& pressed, ReleaseFunction&& released) {
for (size_t i = 0; i != releases; ++i) {
pressed();
released();
2023-07-01 20:34:43 +00:00
}
}
inline void reset() {
presses = releases = 0;
pressed = released = false;
}
2023-07-02 07:19:54 +00:00
inline void press() { pressed = ++presses; held = true; }
inline void release() { released = ++releases; held = false; }
};
2023-07-01 20:34:43 +00:00
struct KeyInputState : InputState {
KeyMod mods = KeyMod::NoMod;
};
struct MouseInputState : InputState {
List<Vec2I> pressPositions;
List<Vec2I> releasePositions;
};
typedef InputState ControllerInputState;
// Get pointer to the singleton Input instance, if it exists. Otherwise,
// returns nullptr.
static Input* singletonPtr();
2023-07-01 20:34:43 +00:00
// Gets reference to Input singleton, throws InputException if root
// is not initialized.
static Input& singleton();
2023-07-01 20:34:43 +00:00
Input();
~Input();
2023-07-01 20:34:43 +00:00
Input(Input const&) = delete;
Input& operator=(Input const&) = delete;
2023-07-01 20:34:43 +00:00
List<std::pair<InputEvent, bool>> const& inputEventsThisFrame() const;
2023-07-02 00:55:25 +00:00
// Clears input state. Should be done at the very start or end of the client loop.
void reset();
2023-07-01 20:34:43 +00:00
void update();
2023-07-02 00:55:25 +00:00
// Handles an input event.
bool handleInput(InputEvent const& input, bool gameProcessed);
2023-07-02 00:55:25 +00:00
void rebuildMappings();
2023-07-01 20:34:43 +00:00
// Loads input categories and their binds from Assets.
void reload();
2023-07-02 07:19:54 +00:00
void setTextInputActive(bool active);
2023-07-02 07:19:54 +00:00
Maybe<unsigned> bindDown(String const& categoryId, String const& bindId);
bool bindHeld(String const& categoryId, String const& bindId);
Maybe<unsigned> bindUp (String const& categoryId, String const& bindId);
2023-07-02 07:19:54 +00:00
Maybe<unsigned> keyDown(Key key, Maybe<KeyMod> keyMod);
bool keyHeld(Key key);
Maybe<unsigned> keyUp (Key key);
Maybe<List<Vec2I>> mouseDown(MouseButton button);
bool mouseHeld(MouseButton button);
Maybe<List<Vec2I>> mouseUp (MouseButton button);
2023-11-01 21:12:21 +00:00
Vec2I mousePosition() const;
void resetBinds(String const& categoryId, String const& bindId);
void setBinds(String const& categoryId, String const& bindId, Json const& binds);
Json getDefaultBinds(String const& categoryId, String const& bindId);
Json getBinds(String const& categoryId, String const& bindId);
private:
List<BindEntry*> filterBindEntries(List<BindRef> const& binds, KeyMod mods) const;
2023-07-02 00:55:25 +00:00
BindEntry* bindEntryPtr(String const& categoryId, String const& bindId);
BindEntry& bindEntry(String const& categoryId, String const& bindId);
2023-07-02 07:19:54 +00:00
InputState* bindStatePtr(String const& categoryId, String const& bindId);
2023-07-02 07:19:54 +00:00
static Input* s_singleton;
2023-07-01 20:34:43 +00:00
// Regenerated on reload.
StableHashMap<String, BindCategory> m_bindCategories;
// Contains raw pointers to bind entries in categories, so also regenerated on reload.
HashMap<InputVariant, List<BindRef>> m_bindMappings;
2023-07-01 20:34:43 +00:00
ListenerPtr m_rootReloadListener;
2023-07-01 20:34:43 +00:00
// Per-frame input event storage for Lua.
List<std::pair<InputEvent, bool>> m_inputEvents;
2023-07-01 20:34:43 +00:00
// Per-frame input state maps.
//Input states
HashMap<Key, KeyInputState> m_keyStates;
HashMap<MouseButton, MouseInputState> m_mouseStates;
HashMap<ControllerButton, ControllerInputState> m_controllerStates;
//Bind states
HashMap<BindEntry const*, InputState> m_bindStates;
KeyMod m_pressedMods;
bool m_textInputActive;
2023-11-01 21:12:21 +00:00
Vec2I m_mousePosition;
};
2023-07-02 07:19:54 +00:00
2023-07-01 20:34:43 +00:00
}
#endif