diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/crepe/api/CMakeLists.txt | 11 | ||||
-rw-r--r-- | src/crepe/api/Event.h | 115 | ||||
-rw-r--r-- | src/crepe/api/EventHandler.cpp | 6 | ||||
-rw-r--r-- | src/crepe/api/EventHandler.h | 115 | ||||
-rw-r--r-- | src/crepe/api/EventHandler.hpp | 27 | ||||
-rw-r--r-- | src/crepe/api/EventManager.cpp | 61 | ||||
-rw-r--r-- | src/crepe/api/EventManager.h | 112 | ||||
-rw-r--r-- | src/crepe/api/EventManager.hpp | 112 | ||||
-rw-r--r-- | src/crepe/api/IKeyListener.cpp | 70 | ||||
-rw-r--r-- | src/crepe/api/IKeyListener.h | 79 | ||||
-rw-r--r-- | src/crepe/api/IMouseListener.cpp | 75 | ||||
-rw-r--r-- | src/crepe/api/IMouseListener.h | 103 | ||||
-rw-r--r-- | src/crepe/api/KeyCodes.h | 222 | ||||
-rw-r--r-- | src/example/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/example/events.cpp | 115 |
15 files changed, 1224 insertions, 0 deletions
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; +} |