aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
m---------lib/sdl20
m---------lib/sdl_image0
m---------lib/sdl_ttf0
-rw-r--r--mwe/events/include/event.h10
-rw-r--r--src/crepe/api/CMakeLists.txt11
-rw-r--r--src/crepe/api/Event.h115
-rw-r--r--src/crepe/api/EventHandler.cpp6
-rw-r--r--src/crepe/api/EventHandler.h115
-rw-r--r--src/crepe/api/EventHandler.hpp27
-rw-r--r--src/crepe/api/EventManager.cpp61
-rw-r--r--src/crepe/api/EventManager.h112
-rw-r--r--src/crepe/api/EventManager.hpp112
-rw-r--r--src/crepe/api/IKeyListener.cpp70
-rw-r--r--src/crepe/api/IKeyListener.h79
-rw-r--r--src/crepe/api/IMouseListener.cpp75
-rw-r--r--src/crepe/api/IMouseListener.h103
-rw-r--r--src/crepe/api/KeyCodes.h222
-rw-r--r--src/example/CMakeLists.txt1
-rw-r--r--src/example/events.cpp115
19 files changed, 1231 insertions, 3 deletions
diff --git a/lib/sdl2 b/lib/sdl2
-Subproject 9519b9916cd29a14587af0507292f2bd31dd575
+Subproject c98c4fbff6d8f3016a3ce6685bf8f43433c3efc
diff --git a/lib/sdl_image b/lib/sdl_image
-Subproject abcf63aa71b4e3ac32120fa9870a6500ddcdcc8
+Subproject 56560190a6c5b5740e5afdce747e2a2bfbf16db
diff --git a/lib/sdl_ttf b/lib/sdl_ttf
-Subproject 4a318f8dfaa1bb6f10e0c5e54052e25d3c7f344
+Subproject a3d0895c1b60c41ff9e85d9203ddd7485c014da
diff --git a/mwe/events/include/event.h b/mwe/events/include/event.h
index ee1bf52..16c75bf 100644
--- a/mwe/events/include/event.h
+++ b/mwe/events/include/event.h
@@ -20,7 +20,9 @@ public: \
static std::uint32_t typeID = UUIDGenerator::getUniqueID(); \
return typeID; \
} \
- virtual std::uint32_t getEventType() const override { return getStaticEventType(); }
+ virtual std::uint32_t getEventType() const override { \
+ return getStaticEventType(); \
+ }
class Event {
public:
Event(std::string eventType);
@@ -30,14 +32,16 @@ public:
void addArgument(const std::string & key,
const std::variant<int, std::string, float> & value);
- std::variant<int, std::string, float> getArgument(const std::string & key) const;
+ std::variant<int, std::string, float>
+ getArgument(const std::string & key) const;
std::string getType() const;
bool getHandled() const;
void markHandled();
private:
- std::unordered_map<std::string, std::variant<int, std::string, float>> eventData;
+ std::unordered_map<std::string, std::variant<int, std::string, float>>
+ eventData;
bool isHandled = false;
};
diff --git a/src/crepe/api/CMakeLists.txt b/src/crepe/api/CMakeLists.txt
index f9b370f..a185ca6 100644
--- a/src/crepe/api/CMakeLists.txt
+++ b/src/crepe/api/CMakeLists.txt
@@ -17,8 +17,12 @@ target_sources(crepe PUBLIC
Vector2.cpp
Camera.cpp
Animator.cpp
+ EventManager.cpp
+ IKeyListener.cpp
+ IMouseListener.cpp
LoopManager.cpp
LoopTimer.cpp
+ EventHandler.cpp
)
target_sources(crepe PUBLIC FILE_SET HEADERS FILES
@@ -43,6 +47,13 @@ target_sources(crepe PUBLIC FILE_SET HEADERS FILES
SceneManager.hpp
Camera.h
Animator.h
+ EventManager.h
+ EventManager.hpp
+ EventHandler.h
+ EventHandler.hpp
+ Event.h
+ IKeyListener.h
+ IMouseListener.h
LoopManager.h
LoopTimer.h
)
diff --git a/src/crepe/api/Event.h b/src/crepe/api/Event.h
new file mode 100644
index 0000000..d5ddf0a
--- /dev/null
+++ b/src/crepe/api/Event.h
@@ -0,0 +1,115 @@
+#pragma once
+
+#include <string>
+
+#include "KeyCodes.h"
+
+/**
+ * \brief Base class for all event types in the system.
+ */
+class Event {
+public:
+};
+
+/**
+ * \brief Event triggered when a key is pressed.
+ */
+class KeyPressEvent : public Event {
+public:
+ //! Number of times the key press is repeated (e.g., for long presses).
+ int repeat = 0;
+
+ //! The key that was pressed.
+ Keycode key = Keycode::NONE;
+};
+
+/**
+ * \brief Event triggered when a key is released.
+ */
+class KeyReleaseEvent : public Event {
+public:
+ //! The key that was released.
+ Keycode key = Keycode::NONE;
+};
+
+/**
+ * \brief Event triggered when a mouse button is pressed.
+ */
+class MousePressEvent : public Event {
+public:
+ //! X-coordinate of the mouse position at the time of the event.
+ int mouse_x = 0;
+
+ //! Y-coordinate of the mouse position at the time of the event.
+ int mouse_y = 0;
+
+ //! The mouse button that was pressed.
+ MouseButton button = MouseButton::NONE;
+};
+
+/**
+ * \brief Event triggered when a mouse button is clicked (press and release).
+ */
+class MouseClickEvent : public Event {
+public:
+ //! X-coordinate of the mouse position at the time of the event.
+ int mouse_x = 0;
+
+ //! Y-coordinate of the mouse position at the time of the event.
+ int mouse_y = 0;
+
+ //! The mouse button that was clicked.
+ MouseButton button = MouseButton::NONE;
+};
+
+/**
+ * \brief Event triggered when a mouse button is released.
+ */
+class MouseReleaseEvent : public Event {
+public:
+ //! X-coordinate of the mouse position at the time of the event.
+ int mouse_x = 0;
+
+ //! Y-coordinate of the mouse position at the time of the event.
+ int mouse_y = 0;
+
+ //! The mouse button that was released.
+ MouseButton button = MouseButton::NONE;
+};
+
+/**
+ * \brief Event triggered when the mouse is moved.
+ */
+class MouseMoveEvent : public Event {
+public:
+ //! X-coordinate of the mouse position at the time of the event.
+ int mouse_x = 0;
+
+ //! Y-coordinate of the mouse position at the time of the event.
+ int mouse_y = 0;
+};
+
+/**
+ * \brief Event triggered during a collision between objects.
+ */
+class CollisionEvent : public Event {
+public:
+ //! Data describing the collision (currently not implemented).
+ // Collision collisionData;
+};
+
+/**
+ * \brief Event triggered when text is submitted, e.g., from a text input.
+ */
+class TextSubmitEvent : public Event {
+public:
+ //! The submitted text.
+ std::string text = "";
+};
+
+/**
+ * \brief Event triggered to indicate the application is shutting down.
+ */
+class ShutDownEvent : public Event {
+public:
+};
diff --git a/src/crepe/api/EventHandler.cpp b/src/crepe/api/EventHandler.cpp
new file mode 100644
index 0000000..186ec9c
--- /dev/null
+++ b/src/crepe/api/EventHandler.cpp
@@ -0,0 +1,6 @@
+#include "EventHandler.h"
+
+using namespace crepe;
+
+// Implementation of IEventHandlerWrapper::exec
+bool IEventHandlerWrapper::exec(const Event & e) { return call(e); }
diff --git a/src/crepe/api/EventHandler.h b/src/crepe/api/EventHandler.h
new file mode 100644
index 0000000..db51d04
--- /dev/null
+++ b/src/crepe/api/EventHandler.h
@@ -0,0 +1,115 @@
+#pragma once
+
+#include <functional>
+#include <string>
+
+#include "Event.h"
+
+namespace crepe {
+/**
+ * \brief A type alias for an event handler function.
+ *
+ * The EventHandler is a std::function that takes an EventType reference and returns a boolean value
+ * indicating whether the event is handled.
+ *
+ * \tparam EventType The type of event this handler will handle.
+ */
+template <typename EventType>
+using EventHandler = std::function<bool(const EventType & e)>;
+
+/**
+ * \class IEventHandlerWrapper
+ * \brief An abstract base class for event handler wrappers.
+ *
+ * This class provides the interface for handling events. Derived classes must implement the
+ * `call()` method to process events and the `get_type()` method to return the handler's type.
+ */
+class IEventHandlerWrapper {
+public:
+ /**
+ * \brief Virtual destructor for IEventHandlerWrapper.
+ */
+ virtual ~IEventHandlerWrapper() = default;
+
+ /**
+ * \brief Executes the handler with the given event.
+ *
+ * This method calls the `call()` method of the derived class, passing the event to the handler.
+ *
+ * \param e The event to be processed.
+ * \return A boolean value indicating whether the event is handled.
+ */
+ bool exec(const Event & e);
+
+ /**
+ * \brief Get the type of the event handler.
+ *
+ * This method returns the type of the event handler as a string.
+ *
+ * \return A string representing the handler's type.
+ */
+ virtual std::string get_type() const = 0;
+
+private:
+ /**
+ * \brief The method responsible for handling the event.
+ *
+ * This method is implemented by derived classes to process the event.
+ *
+ * \param e The event to be processed.
+ * \return A boolean value indicating whether the event is handled.
+ */
+ virtual bool call(const Event & e) = 0;
+};
+
+/**
+ * \class EventHandlerWrapper
+ * \brief A wrapper for event handler functions.
+ *
+ * This class wraps an event handler function of a specific event type. It implements the
+ * `call()` and `get_type()` methods to allow the handler to be executed and its type to be
+ * queried.
+ *
+ * \tparam EventType The type of event this handler will handle.
+ */
+template <typename EventType>
+class EventHandlerWrapper : public IEventHandlerWrapper {
+public:
+ /**
+ * \brief Constructs an EventHandlerWrapper with a given handler.
+ *
+ * The constructor takes an event handler function and stores it in the wrapper.
+ *
+ * \param handler The event handler function.
+ */
+ explicit EventHandlerWrapper(const EventHandler<EventType> & handler);
+
+private:
+ /**
+ * \brief Calls the stored event handler with the event.
+ *
+ * This method casts the event to the appropriate type and calls the handler.
+ *
+ * \param e The event to be handled.
+ * \return A boolean value indicating whether the event is handled.
+ */
+ bool call(const Event & e) override;
+
+ /**
+ * \brief Returns the type of the handler.
+ *
+ * This method returns a string representing the type of the event handler.
+ *
+ * \return The handler type as a string.
+ */
+ std::string get_type() const override;
+
+ //! The event handler function.
+ EventHandler<EventType> m_handler;
+ //! The type name of the handler function.
+ const std::string m_handler_type;
+};
+
+} // namespace crepe
+
+#include "EventHandler.hpp"
diff --git a/src/crepe/api/EventHandler.hpp b/src/crepe/api/EventHandler.hpp
new file mode 100644
index 0000000..564d3d7
--- /dev/null
+++ b/src/crepe/api/EventHandler.hpp
@@ -0,0 +1,27 @@
+
+#include <typeindex>
+
+#include "EventHandler.h"
+
+namespace crepe {
+
+// Implementation of EventHandlerWrapper constructor
+template <typename EventType>
+EventHandlerWrapper<EventType>::EventHandlerWrapper(
+ const EventHandler<EventType> & handler)
+ : m_handler(handler),
+ m_handler_type(m_handler.target_type().name()) {}
+
+// Implementation of EventHandlerWrapper::call
+template <typename EventType>
+bool EventHandlerWrapper<EventType>::call(const Event & e) {
+ return m_handler(static_cast<const EventType &>(e));
+}
+
+// Implementation of EventHandlerWrapper::get_type
+template <typename EventType>
+std::string EventHandlerWrapper<EventType>::get_type() const {
+ return m_handler_type;
+}
+
+} //namespace crepe
diff --git a/src/crepe/api/EventManager.cpp b/src/crepe/api/EventManager.cpp
new file mode 100644
index 0000000..7f47938
--- /dev/null
+++ b/src/crepe/api/EventManager.cpp
@@ -0,0 +1,61 @@
+#include "EventManager.h"
+
+using namespace crepe;
+
+EventManager & EventManager::get_instance() {
+ static EventManager instance;
+ return instance;
+}
+
+void EventManager::dispatch_events() {
+ using HandlersMap = std::unordered_map<
+ int, std::vector<std::unique_ptr<IEventHandlerWrapper>>>;
+ using HandlersVec = std::vector<std::unique_ptr<IEventHandlerWrapper>>;
+
+ for (auto event_it = this->events_queue.begin();
+ event_it != this->events_queue.end();) {
+ std::unique_ptr<Event> & event = std::get<0>(*event_it);
+ int channel = std::get<1>(*event_it);
+ std::type_index event_type = std::get<2>(*event_it);
+
+ bool event_handled = false;
+
+ if (channel) {
+ auto handlers_it = subscribers_by_event_id.find(event_type);
+ if (handlers_it != subscribers_by_event_id.end()) {
+ HandlersMap & handlers_map = handlers_it->second;
+ auto handlers = handlers_map.find(channel);
+ if (handlers != handlers_map.end()) {
+ HandlersVec & callbacks = handlers->second;
+ for (auto handler_it = callbacks.begin();
+ handler_it != callbacks.end(); ++handler_it) {
+ if ((*handler_it)->exec(*event)) {
+ event_it = events_queue.erase(event_it);
+ event_handled = true;
+ break;
+ }
+ }
+ }
+ }
+ } else {
+ // Handle event for all channels
+ auto handlers_it = this->subscribers.find(event_type);
+ if (handlers_it != this->subscribers.end()) {
+ HandlersVec & handlers = handlers_it->second;
+ for (auto handler_it = handlers.begin();
+ handler_it != handlers.end(); ++handler_it) {
+ // remove event from queue since and continue when callback returns true
+ if ((*handler_it)->exec(*event)) {
+ event_it = this->events_queue.erase(event_it);
+ event_handled = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if (!event_handled) {
+ ++event_it;
+ }
+ }
+}
diff --git a/src/crepe/api/EventManager.h b/src/crepe/api/EventManager.h
new file mode 100644
index 0000000..783db62
--- /dev/null
+++ b/src/crepe/api/EventManager.h
@@ -0,0 +1,112 @@
+#pragma once
+
+#include <functional>
+#include <memory>
+#include <type_traits>
+#include <typeindex>
+#include <unordered_map>
+#include <vector>
+
+#include "Event.h"
+#include "EventHandler.h"
+
+namespace crepe {
+
+/**
+ * \class EventManager
+ * \brief The EventManager class is responsible for managing the subscription, triggering,
+ * and queueing of events. It handles events and dispatches them to appropriate subscribers.
+ */
+class EventManager {
+public:
+ /**
+ * \brief Get the singleton instance of the EventManager.
+ *
+ * This method returns the unique instance of the EventManager, creating it on the first call.
+ *
+ * \return Reference to the EventManager instance.
+ */
+ static EventManager & get_instance();
+
+ /**
+ * \brief Subscribe to an event.
+ *
+ * This method allows the registration of a callback for a specific event type and channel.
+ *
+ * \tparam EventType The type of the event to subscribe to.
+ * \param callback The callback function to invoke when the event is triggered.
+ * \param channel The channel number to subscribe to (default is 0).
+ */
+ template <typename EventType>
+ void subscribe(EventHandler<EventType> && callback, int channel = 0);
+
+ /**
+ * \brief Unsubscribe from an event.
+ *
+ * This method removes a previously registered callback from an event.
+ *
+ * \tparam EventType The type of the event to unsubscribe from.
+ * \param callback The callback function to remove from the subscription list.
+ * \param channel The event ID to unsubscribe from.
+ */
+ template <typename EventType>
+ void unsubscribe(const EventHandler<EventType> &, int channel);
+
+ /**
+ * \brief Trigger an event.
+ *
+ * This method invokes the appropriate callback(s) for the specified event.
+ *
+ * \tparam EventType The type of the event to trigger.
+ * \param event The event data to pass to the callback.
+ * \param channel The channel from which to trigger the event (default is 0).
+ */
+ template <typename EventType>
+ void trigger_event(const EventType & event, int channel);
+
+ /**
+ * \brief Queue an event for later processing.
+ *
+ * This method adds an event to the event queue, which will be processed in the
+ * dispatch_events function.
+ *
+ * \tparam EventType The type of the event to queue.
+ * \param event The event to queue.
+ * \param channel The channel number for the event (default is 0).
+ */
+ template <typename EventType>
+ void queue_event(EventType && event, int channel);
+
+ /**
+ * \brief Dispatch all queued events.
+ *
+ * This method processes all events in the event queue and triggers the corresponding
+ * callbacks for each event.
+ */
+ void dispatch_events();
+
+private:
+ /**
+ * \brief Default constructor for the EventManager.
+ *
+ * This constructor is private to enforce the singleton pattern.
+ */
+ EventManager() = default;
+
+ //! The queue of events to be processed.
+ std::vector<std::tuple<std::unique_ptr<Event>, int, std::type_index>>
+ events_queue;
+ //! Registered event handlers.
+ std::unordered_map<std::type_index,
+ std::vector<std::unique_ptr<IEventHandlerWrapper>>>
+ subscribers;
+ //! Event handlers indexed by event ID.
+ std::unordered_map<
+ std::type_index,
+ std::unordered_map<int,
+ std::vector<std::unique_ptr<IEventHandlerWrapper>>>>
+ subscribers_by_event_id;
+};
+
+} // namespace crepe
+#include "EventManager.hpp"
diff --git a/src/crepe/api/EventManager.hpp b/src/crepe/api/EventManager.hpp
new file mode 100644
index 0000000..d901492
--- /dev/null
+++ b/src/crepe/api/EventManager.hpp
@@ -0,0 +1,112 @@
+#include "EventManager.h"
+
+namespace crepe {
+
+template <typename EventType>
+void EventManager::subscribe(EventHandler<EventType> && callback, int channel) {
+ using HandlersMap = std::unordered_map<
+ int, std::vector<std::unique_ptr<IEventHandlerWrapper>>>;
+ using HandlersVec = std::vector<std::unique_ptr<IEventHandlerWrapper>>;
+
+ std::type_index event_type = typeid(EventType);
+ std::unique_ptr<EventHandlerWrapper<EventType>> handler
+ = std::make_unique<EventHandlerWrapper<EventType>>(callback);
+
+ if (channel) {
+ HandlersMap & handlers_map = this->subscribers_by_event_id[event_type];
+ auto handlers = handlers_map.find(channel);
+ if (handlers != handlers_map.end()) {
+ handlers->second.emplace_back(std::move(handler));
+ } else {
+ handlers_map[channel].emplace_back(std::move(handler));
+ }
+ } else {
+ HandlersVec & handlers = this->subscribers[event_type];
+ handlers.emplace_back(std::move(handler));
+ }
+}
+
+template <typename EventType>
+void EventManager::queue_event(EventType && event, int channel) {
+ std::type_index event_type = std::type_index(typeid(EventType));
+
+ auto event_ptr
+ = std::make_unique<EventType>(std::forward<EventType>(event));
+
+ std::tuple<std::unique_ptr<Event>, int, std::type_index> tuple(
+ std::move(event_ptr), channel, event_type);
+ this->events_queue.push_back(std::move(tuple));
+}
+
+template <typename EventType>
+void EventManager::trigger_event(const EventType & event, int channel) {
+ using HandlersMap = std::unordered_map<
+ int, std::vector<std::unique_ptr<IEventHandlerWrapper>>>;
+ using HandlersVec = std::vector<std::unique_ptr<IEventHandlerWrapper>>;
+
+ std::type_index event_type = std::type_index(typeid(EventType));
+
+ if (channel > 0) {
+ HandlersMap & handlers_map = this->subscribers_by_event_id[event_type];
+ auto handlers_it = handlers_map.find(channel);
+
+ if (handlers_it != handlers_map.end()) {
+ HandlersVec & handlers = handlers_it->second;
+ for (auto it = handlers.begin(); it != handlers.end(); ++it) {
+ // stops when callback returns true
+ if ((*it)->exec(event)) {
+ break;
+ }
+ }
+ }
+ } else {
+ HandlersVec & handlers = this->subscribers[event_type];
+ for (auto it = handlers.begin(); it != handlers.end(); ++it) {
+ // stops when callback returns true
+ if ((*it)->exec(event)) {
+ break;
+ }
+ }
+ }
+}
+
+template <typename EventType>
+void EventManager::unsubscribe(const EventHandler<EventType> & callback,
+ int channel) {
+ using HandlersMap = std::unordered_map<
+ int, std::vector<std::unique_ptr<IEventHandlerWrapper>>>;
+ using HandlersVec = std::vector<std::unique_ptr<IEventHandlerWrapper>>;
+
+ std::type_index event_type(typeid(EventType));
+ std::string handler_name = callback.target_type().name();
+
+ if (channel) {
+ auto subscriber_list = this->subscribers_by_event_id.find(event_type);
+ if (subscriber_list != this->subscribers_by_event_id.end()) {
+ HandlersMap & handlers_map = subscriber_list->second;
+ auto handlers = handlers_map.find(channel);
+ if (handlers != handlers_map.end()) {
+ HandlersVec & callbacks = handlers->second;
+ for (auto it = callbacks.begin(); it != callbacks.end(); ++it) {
+ if ((*it)->get_type() == handler_name) {
+ it = callbacks.erase(it);
+ return;
+ }
+ }
+ }
+ }
+ } else {
+ auto handlers_it = this->subscribers.find(event_type);
+ if (handlers_it != this->subscribers.end()) {
+ HandlersVec & handlers = handlers_it->second;
+ for (auto it = handlers.begin(); it != handlers.end(); ++it) {
+ if ((*it)->get_type() == handler_name) {
+ it = handlers.erase(it);
+ return;
+ }
+ }
+ }
+ }
+}
+
+} // namespace crepe
diff --git a/src/crepe/api/IKeyListener.cpp b/src/crepe/api/IKeyListener.cpp
new file mode 100644
index 0000000..cd255df
--- /dev/null
+++ b/src/crepe/api/IKeyListener.cpp
@@ -0,0 +1,70 @@
+#include "IKeyListener.h"
+
+using namespace crepe;
+
+// Constructor with default channel
+IKeyListener::IKeyListener()
+ : channel(0),
+ active(true),
+ event_manager(EventManager::get_instance()) {
+ this->subscribe_events();
+}
+
+// Constructor with specified channel
+IKeyListener::IKeyListener(int channel)
+ : channel(channel),
+ active(true),
+ event_manager(EventManager::get_instance()) {
+ this->subscribe_events();
+}
+
+// Destructor, unsubscribe events
+IKeyListener::~IKeyListener() { this->unsubscribe_events(); }
+
+// Subscribe to key events
+void IKeyListener::subscribe_events() {
+ key_pressed_handler = [this](const KeyPressEvent & event) {
+ return this->on_key_pressed(event);
+ };
+ key_released_handler = [this](const KeyReleaseEvent & event) {
+ return this->on_key_released(event);
+ };
+
+ event_manager.subscribe<KeyPressEvent>(std::move(this->key_pressed_handler),
+ this->channel);
+ event_manager.subscribe<KeyReleaseEvent>(
+ std::move(this->key_released_handler), this->channel);
+}
+
+// Unsubscribe from key events
+void IKeyListener::unsubscribe_events() {
+ event_manager.unsubscribe<KeyPressEvent>(this->key_pressed_handler,
+ this->channel);
+ event_manager.unsubscribe<KeyReleaseEvent>(this->key_released_handler,
+ this->channel);
+}
+
+// Activate key listening
+void IKeyListener::activate_keys() {
+ if (this->active) {
+ return;
+ }
+ this->active = true;
+ this->subscribe_events();
+}
+
+// Deactivate key listening
+void IKeyListener::deactivate_keys() {
+ if (!this->active) {
+ return;
+ }
+ this->active = false;
+ this->unsubscribe_events();
+}
+
+// Set a new channel for key events
+void IKeyListener::set_channel(int channel) {
+ this->unsubscribe_events();
+ this->channel = channel;
+ this->subscribe_events();
+}
diff --git a/src/crepe/api/IKeyListener.h b/src/crepe/api/IKeyListener.h
new file mode 100644
index 0000000..3e0e2cb
--- /dev/null
+++ b/src/crepe/api/IKeyListener.h
@@ -0,0 +1,79 @@
+#pragma once
+
+#include "Event.h"
+#include "EventHandler.h"
+#include "EventManager.h"
+
+namespace crepe {
+
+/**
+ * \class IKeyListener
+ * \brief Interface for keyboard event handling in the application.
+ */
+class IKeyListener {
+public:
+ /**
+ * \brief Constructs an IKeyListener with a specified channel.
+ * \param channel The channel ID for event handling.
+ */
+ IKeyListener(int channel);
+ IKeyListener();
+ virtual ~IKeyListener();
+ IKeyListener(const IKeyListener &) = delete;
+ IKeyListener & operator=(const IKeyListener &) = delete;
+ IKeyListener(IKeyListener &&) = delete;
+
+ /**
+ * \brief Pure virtual function to handle key press events.
+ * \param event The key press event to handle.
+ * \return True if the event was handled, false otherwise.
+ */
+ virtual bool on_key_pressed(const KeyPressEvent & event) = 0;
+
+ /**
+ * \brief Pure virtual function to handle key release events.
+ * \param event The key release event to handle.
+ * \return True if the event was handled, false otherwise.
+ */
+ virtual bool on_key_released(const KeyReleaseEvent & event) = 0;
+
+ /**
+ * \brief Activates key listening.
+ */
+ void activate_keys();
+
+ /**
+ * \brief Deactivates key listening.
+ */
+ void deactivate_keys();
+
+ /**
+ * \brief Sets the channel ID for event handling.
+ * \param channel The channel ID to set.
+ */
+ void set_channel(int channel);
+
+protected:
+ /**
+ * \brief Subscribes to key events.
+ */
+ void subscribe_events();
+
+ /**
+ * \brief Unsubscribes from key events.
+ */
+ void unsubscribe_events();
+
+private:
+ //! Indicates whether key listening is active.
+ bool active = true;
+ //! Channel ID for event handling.
+ int channel = 0;
+ //! Key press event handler.
+ EventHandler<KeyPressEvent> key_pressed_handler;
+ //!< Key release event handler.
+ EventHandler<KeyReleaseEvent> key_released_handler;
+ EventManager & event_manager;
+};
+
+} // namespace crepe
diff --git a/src/crepe/api/IMouseListener.cpp b/src/crepe/api/IMouseListener.cpp
new file mode 100644
index 0000000..bfa49f8
--- /dev/null
+++ b/src/crepe/api/IMouseListener.cpp
@@ -0,0 +1,75 @@
+#include "IMouseListener.h"
+
+using namespace crepe;
+
+IMouseListener::IMouseListener(int channel)
+ : event_manager(EventManager::get_instance()),
+ channel(channel) {
+ this->subscribe_events();
+}
+
+IMouseListener::IMouseListener() : event_manager(EventManager::get_instance()) {
+ this->subscribe_events();
+}
+
+IMouseListener::~IMouseListener() { this->unsubscribe_events(); }
+
+void IMouseListener::subscribe_events() {
+ // Define handler lambdas and subscribe them
+ mouse_click_handler = [this](const MouseClickEvent & event) {
+ return this->on_mouse_clicked(event);
+ };
+ mouse_press_handler = [this](const MousePressEvent & event) {
+ return this->on_mouse_pressed(event);
+ };
+ mouse_release_handler = [this](const MouseReleaseEvent & event) {
+ return this->on_mouse_released(event);
+ };
+ mouse_move_handler = [this](const MouseMoveEvent & event) {
+ return this->on_mouse_moved(event);
+ };
+
+ // Subscribe event handlers (no need for std::move)
+ event_manager.subscribe<MouseClickEvent>(std::move(mouse_click_handler),
+ this->channel);
+ event_manager.subscribe<MousePressEvent>(std::move(mouse_press_handler),
+ this->channel);
+ event_manager.subscribe<MouseReleaseEvent>(std::move(mouse_release_handler),
+ this->channel);
+ event_manager.subscribe<MouseMoveEvent>(std::move(mouse_move_handler),
+ this->channel);
+}
+
+void IMouseListener::unsubscribe_events() {
+ // Unsubscribe event handlers
+ event_manager.unsubscribe<MouseClickEvent>(mouse_click_handler,
+ this->channel);
+ event_manager.unsubscribe<MousePressEvent>(mouse_press_handler,
+ this->channel);
+ event_manager.unsubscribe<MouseReleaseEvent>(mouse_release_handler,
+ this->channel);
+ event_manager.unsubscribe<MouseMoveEvent>(mouse_move_handler,
+ this->channel);
+}
+
+void IMouseListener::activate_mouse() {
+ if (this->active) {
+ return;
+ }
+ this->subscribe_events();
+ this->active = true;
+}
+
+void IMouseListener::deactivate_mouse() {
+ if (!this->active) {
+ return;
+ }
+ this->unsubscribe_events();
+ this->active = false;
+}
+
+void IMouseListener::set_channel(int channel) {
+ this->unsubscribe_events();
+ this->channel = channel;
+ this->subscribe_events();
+}
diff --git a/src/crepe/api/IMouseListener.h b/src/crepe/api/IMouseListener.h
new file mode 100644
index 0000000..2ec156f
--- /dev/null
+++ b/src/crepe/api/IMouseListener.h
@@ -0,0 +1,103 @@
+#pragma once
+
+#include "Event.h"
+#include "EventHandler.h"
+#include "EventManager.h"
+
+namespace crepe {
+
+/**
+ * \class IMouseListener
+ * \brief Interface for mouse event handling in the application.
+ */
+class IMouseListener {
+public:
+
+ IMouseListener();
+ /**
+ * \brief Constructs an IMouseListener with a specified channel.
+ * \param channel The channel ID for event handling.
+ */
+ IMouseListener(int channel);
+ virtual ~IMouseListener();
+ IMouseListener(const IMouseListener &) = delete;
+ IMouseListener & operator=(const IMouseListener &) = delete;
+ IMouseListener(IMouseListener &&) = delete;
+
+ /**
+ * \brief Move assignment operator (deleted).
+ */
+ IMouseListener & operator=(IMouseListener &&) = delete;
+
+ /**
+ * \brief Handles a mouse click event.
+ * \param event The mouse click event to handle.
+ * \return True if the event was handled, false otherwise.
+ */
+ virtual bool on_mouse_clicked(const MouseClickEvent & event) = 0;
+
+ /**
+ * \brief Handles a mouse press event.
+ * \param event The mouse press event to handle.
+ * \return True if the event was handled, false otherwise.
+ */
+ virtual bool on_mouse_pressed(const MousePressEvent & event) = 0;
+
+ /**
+ * \brief Handles a mouse release event.
+ * \param event The mouse release event to handle.
+ * \return True if the event was handled, false otherwise.
+ */
+ virtual bool on_mouse_released(const MouseReleaseEvent & event) = 0;
+
+ /**
+ * \brief Handles a mouse move event.
+ * \param event The mouse move event to handle.
+ * \return True if the event was handled, false otherwise.
+ */
+ virtual bool on_mouse_moved(const MouseMoveEvent & event) = 0;
+
+ /**
+ * \brief Activates mouse listening.
+ */
+ void activate_mouse();
+
+ /**
+ * \brief Deactivates mouse listening.
+ */
+ void deactivate_mouse();
+
+ /**
+ * \brief Sets the channel ID for event handling.
+ * \param channel The channel ID to set.
+ */
+ void set_channel(int channel);
+
+protected:
+ /**
+ * \brief Subscribes to mouse events on the specified channel.
+ */
+ void subscribe_events();
+
+ /**
+ * \brief Unsubscribes from mouse events on the specified channel.
+ */
+ void unsubscribe_events();
+
+private:
+ //! Indicates whether mouse listening is active.
+ bool active = true;
+ //! Channel ID for event handling.
+ int channel = 0;
+ //! Mouse click event handler.
+ EventHandler<MouseClickEvent> mouse_click_handler;
+ //! Mouse press event handler.
+ EventHandler<MousePressEvent> mouse_press_handler;
+ //! Mouse release event handler.
+ EventHandler<MouseReleaseEvent> mouse_release_handler;
+ //! Mouse move event handler.
+ EventHandler<MouseMoveEvent> mouse_move_handler;
+ EventManager & event_manager;
+};
+
+} //namespace crepe
diff --git a/src/crepe/api/KeyCodes.h b/src/crepe/api/KeyCodes.h
new file mode 100644
index 0000000..feed0b2
--- /dev/null
+++ b/src/crepe/api/KeyCodes.h
@@ -0,0 +1,222 @@
+#pragma once
+
+//! \enum MouseButton
+//! \brief Enumeration for mouse button inputs, including standard and extended buttons.
+enum class MouseButton {
+ //! No mouse button input.
+ NONE = 0,
+ //! Left mouse button.
+ LEFT_MOUSE = 1,
+ //! Right mouse button.
+ RIGHT_MOUSE = 2,
+ //! Middle mouse button (scroll wheel press).
+ MIDDLE_MOUSE = 3,
+ //! First extended mouse button.
+ X1_MOUSE = 4,
+ //! Second extended mouse button.
+ X2_MOUSE = 5,
+ //! Scroll wheel upward movement.
+ SCROLL_UP = 6,
+ //! Scroll wheel downward movement.
+ SCROLL_DOWN = 7
+};
+
+//! \enum Keycode
+//! \brief Enumeration for keyboard key inputs, including printable characters, function keys, and keypad keys.
+enum class Keycode : int {
+ //! No key input.
+ NONE = 0,
+ //! Spacebar.
+ SPACE = 32,
+ //! Apostrophe (').
+ APOSTROPHE = 39,
+ //! Comma (,).
+ COMMA = 44,
+ //! Minus (-).
+ MINUS = 45,
+ //! Period (.).
+ PERIOD = 46,
+ //! Slash (/).
+ SLASH = 47,
+ //! Digit 0.
+ D0 = 48,
+ //! Digit 1.
+ D1 = 49,
+ //! Digit 2.
+ D2 = 50,
+ //! Digit 3.
+ D3 = 51,
+ //! Digit 4.
+ D4 = 52,
+ //! Digit 5.
+ D5 = 53,
+ //! Digit 6.
+ D6 = 54,
+ //! Digit 7.
+ D7 = 55,
+ //! Digit 8.
+ D8 = 56,
+ //! Digit 9.
+ D9 = 57,
+ //! Semicolon (;).
+ SEMICOLON = 59,
+ //! Equal sign (=).
+ EQUAL = 61,
+ //! Key 'A'.
+ A = 65,
+ //! Key 'B'.
+ B = 66,
+ //! Key 'C'.
+ C = 67,
+ //! Key 'D'.
+ D = 68,
+ //! Key 'E'.
+ E = 69,
+ //! Key 'F'.
+ F = 70,
+ //! Key 'G'.
+ G = 71,
+ //! Key 'H'.
+ H = 72,
+ //! Key 'I'.
+ I = 73,
+ //! Key 'J'.
+ J = 74,
+ //! Key 'K'.
+ K = 75,
+ //! Key 'L'.
+ L = 76,
+ //! Key 'M'.
+ M = 77,
+ //! Key 'N'.
+ N = 78,
+ //! Key 'O'.
+ O = 79,
+ //! Key 'P'.
+ P = 80,
+ //! Key 'Q'.
+ Q = 81,
+ //! Key 'R'.
+ R = 82,
+ //! Key 'S'.
+ S = 83,
+ //! Key 'T'.
+ T = 84,
+ //! Key 'U'.
+ U = 85,
+ //! Key 'V'.
+ V = 86,
+ //! Key 'W'.
+ W = 87,
+ //! Key 'X'.
+ X = 88,
+ //! Key 'Y'.
+ Y = 89,
+ //! Key 'Z'.
+ Z = 90,
+ //! Left bracket ([).
+ LEFT_BRACKET = 91,
+ //! Backslash (\).
+ BACKSLASH = 92,
+ //! Right bracket (]).
+ RIGHT_BRACKET = 93,
+ //! Grave accent (`).
+ GRAVE_ACCENT = 96,
+ //! Non-US key #1.
+ WORLD1 = 161,
+ //! Non-US key #2.
+ WORLD2 = 162,
+ //! Escape key.
+ ESCAPE = 256,
+ //! Enter key.
+ ENTER = 257,
+ //! Tab key.
+ TAB = 258,
+ //! Backspace key.
+ BACKSPACE = 259,
+ //! Insert key.
+ INSERT = 260,
+ //! Delete key.
+ DELETE = 261,
+ //! Right arrow key.
+ RIGHT = 262,
+ //! Left arrow key.
+ LEFT = 263,
+ //! Down arrow key.
+ DOWN = 264,
+ //! Up arrow key.
+ UP = 265,
+ //! Page Up key.
+ PAGE_UP = 266,
+ //! Page Down key.
+ PAGE_DOWN = 267,
+ //! Home key.
+ HOME = 268,
+ //! End key.
+ END = 269,
+ //! Caps Lock key.
+ CAPS_LOCK = 280,
+ //! Scroll Lock key.
+ SCROLL_LOCK = 281,
+ //! Num Lock key.
+ NUM_LOCK = 282,
+ //! Print Screen key.
+ PRINT_SCREEN = 283,
+ //! Pause key.
+ PAUSE = 284,
+ //! Function keys (F1-F25).
+ F1 = 290,
+ F2 = 291,
+ F3 = 292,
+ F4 = 293,
+ F5 = 294,
+ F6 = 295,
+ F7 = 296,
+ F8 = 297,
+ F9 = 298,
+ F10 = 299,
+ F11 = 300,
+ F12 = 301,
+ F13 = 302,
+ F14 = 303,
+ F15 = 304,
+ F16 = 305,
+ F17 = 306,
+ F18 = 307,
+ F19 = 308,
+ F20 = 309,
+ F21 = 310,
+ F22 = 311,
+ F23 = 312,
+ F24 = 313,
+ F25 = 314,
+ //! Keypad digits and operators.
+ KP0 = 320,
+ KP1 = 321,
+ KP2 = 322,
+ KP3 = 323,
+ KP4 = 324,
+ KP5 = 325,
+ KP6 = 326,
+ KP7 = 327,
+ KP8 = 328,
+ KP9 = 329,
+ KP_DECIMAL = 330,
+ KP_DIVIDE = 331,
+ KP_MULTIPLY = 332,
+ KP_SUBTRACT = 333,
+ KP_ADD = 334,
+ KP_ENTER = 335,
+ KP_EQUAL = 336,
+ //! Modifier keys.
+ LEFT_SHIFT = 340,
+ LEFT_CONTROL = 341,
+ LEFT_ALT = 342,
+ LEFT_SUPER = 343,
+ RIGHT_SHIFT = 344,
+ RIGHT_CONTROL = 345,
+ RIGHT_ALT = 346,
+ RIGHT_SUPER = 347,
+ //! Menu key.
+ MENU = 348
+};
diff --git a/src/example/CMakeLists.txt b/src/example/CMakeLists.txt
index 3a5b543..ddb0262 100644
--- a/src/example/CMakeLists.txt
+++ b/src/example/CMakeLists.txt
@@ -28,6 +28,7 @@ add_example(proxy)
add_example(db)
add_example(ecs)
add_example(scene_manager)
+add_example(events)
add_example(particles)
add_example(gameloop)
diff --git a/src/example/events.cpp b/src/example/events.cpp
new file mode 100644
index 0000000..5a0a748
--- /dev/null
+++ b/src/example/events.cpp
@@ -0,0 +1,115 @@
+#include <iostream>
+
+#include <crepe/ComponentManager.h>
+#include <crepe/system/ScriptSystem.h>
+#include <crepe/util/log.h>
+
+#include <crepe/api/BehaviorScript.h>
+#include <crepe/api/Config.h>
+#include <crepe/api/Event.h>
+#include <crepe/api/EventManager.h>
+#include <crepe/api/GameObject.h>
+#include <crepe/api/IKeyListener.h>
+#include <crepe/api/IMouseListener.h>
+#include <crepe/api/KeyCodes.h>
+#include <crepe/api/Script.h>
+#include <crepe/api/Transform.h>
+
+using namespace crepe;
+using namespace std;
+
+class MyScript : public Script, public IKeyListener, public IMouseListener {
+ void update() {
+ // Retrieve component from the same GameObject this script is on
+ Transform & test = get_component<Transform>();
+ dbg_logf("Transform(%.2f, %.2f)", test.position.x, test.position.y);
+ }
+
+ bool on_key_pressed(const KeyPressEvent & event) override {
+ std::cout << "KeyPressed function" << std::endl;
+ this->deactivate_keys();
+ return false;
+ }
+ bool on_key_released(const KeyReleaseEvent & event) override {
+ std::cout << "KeyRelease function" << std::endl;
+ return false;
+ }
+ bool on_mouse_clicked(const MouseClickEvent & event) override {
+ std::cout << "MouseClick function" << std::endl;
+ return false;
+ }
+ bool on_mouse_pressed(const MousePressEvent & event) override {
+ std::cout << "MousePress function" << std::endl;
+ return false;
+ }
+ bool on_mouse_released(const MouseReleaseEvent & event) override {
+ std::cout << "MouseRelease function" << std::endl;
+ return false;
+ }
+ bool on_mouse_moved(const MouseMoveEvent & event) override {
+ std::cout << "MouseMove function" << std::endl;
+ return false;
+ }
+};
+class TestKeyListener : public IKeyListener {
+public:
+ bool on_key_pressed(const KeyPressEvent & event) override {
+ std::cout << "TestKeyListener: Key Pressed - Code: "
+ << static_cast<int>(event.key) << std::endl;
+ return true; // Return true if the listener should remain active
+ }
+ bool on_key_released(const KeyReleaseEvent & event) override {
+ std::cout << "TestKeyListener: Key Released - Code: "
+ << static_cast<int>(event.key) << std::endl;
+ return true;
+ }
+};
+int main() {
+ // two events to trigger
+ KeyPressEvent key_press;
+ key_press.key = Keycode::A;
+ key_press.repeat = 0;
+ MouseClickEvent click_event;
+ click_event.button = MouseButton::LEFT_MOUSE;
+ click_event.mouse_x = 100;
+ click_event.mouse_y = 200;
+ // queue events to test queue
+ EventManager::get_instance().queue_event<KeyPressEvent>(
+ std::move(key_press), 0);
+ EventManager::get_instance().queue_event<MouseClickEvent>(
+ std::move(click_event), 0);
+ {
+ TestKeyListener test_listener;
+ test_listener.set_channel(1);
+ auto obj = GameObject(0, "name", "tag", Vector2{1.2, 3.4}, 0, 1);
+ obj.add_component<BehaviorScript>().set_script<MyScript>();
+
+ ScriptSystem sys;
+ sys.update();
+
+ // Trigger the events while `testListener` is in scope
+ EventManager::get_instance().trigger_event<KeyPressEvent>(key_press, 1);
+ EventManager::get_instance().trigger_event(
+ MouseClickEvent{
+ .mouse_x = 100,
+ .mouse_y = 100,
+ .button = MouseButton::LEFT_MOUSE,
+ },
+ 1);
+ }
+ // custom lambda event handler
+ EventHandler<KeyPressEvent> event_handler = [](const KeyPressEvent & e) {
+ std::cout << "lambda test" << std::endl;
+ return false;
+ };
+ EventManager::get_instance().subscribe<KeyPressEvent>(
+ std::move(event_handler), 0);
+ // testing trigger with testListener not in scope (unsubscribed)
+ EventManager::get_instance().trigger_event<KeyPressEvent>(key_press, 0);
+ EventManager::get_instance().trigger_event<MouseClickEvent>(click_event, 0);
+ // dispatching queued events
+ EventManager::get_instance().dispatch_events();
+
+ EventManager::get_instance().unsubscribe<KeyPressEvent>(event_handler, 0);
+ return EXIT_SUCCESS;
+}