@ -1,74 +0,0 @@ | |||
/* | |||
* Copyright (C) 2023 Christopher J. Howard | |||
* | |||
* This file is part of Antkeeper source code. | |||
* | |||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation, either version 3 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* Antkeeper source code is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License | |||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | |||
#ifndef ANTKEEPER_DEBUG_ANSI_CODES_HPP | |||
#define ANTKEEPER_DEBUG_ANSI_CODES_HPP | |||
namespace debug { | |||
/// ANSI escape codes. | |||
namespace ansi { | |||
constexpr char* reset = "\u004b[0m"; | |||
constexpr char* black = "\u003b[30m"; | |||
constexpr char* red = "\u003b[31m"; | |||
constexpr char* green = "\u003b[32m"; | |||
constexpr char* yellow = "\u003b[33m"; | |||
constexpr char* blue = "\u003b[34m"; | |||
constexpr char* magenta = "\u003b[35m"; | |||
constexpr char* cyan = "\u003b[36m"; | |||
constexpr char* white = "\u003b[37m"; | |||
constexpr char* bright_black = "\u003b[30;1m"; | |||
constexpr char* bright_red = "\u003b[31;1m"; | |||
constexpr char* bright_green = "\u003b[32;1m"; | |||
constexpr char* bright_yellow = "\u003b[33;1m"; | |||
constexpr char* bright_blue = "\u003b[34;1m"; | |||
constexpr char* bright_magenta = "\u003b[35;1m"; | |||
constexpr char* bright_cyan = "\u003b[36;1m"; | |||
constexpr char* bright_white = "\u003b[37;1m"; | |||
constexpr char* background_black = "\u003b[40m"; | |||
constexpr char* background_red = "\u003b[41m"; | |||
constexpr char* background_green = "\u003b[42m"; | |||
constexpr char* background_yellow = "\u003b[43m"; | |||
constexpr char* background_blue = "\u003b[44m"; | |||
constexpr char* background_magenta = "\u003b[45m"; | |||
constexpr char* background_cyan = "\u003b[46m"; | |||
constexpr char* background_white = "\u003b[47m"; | |||
constexpr char* background_bright_black = "\u003b[40;1m"; | |||
constexpr char* background_bright_red = "\u003b[41;1m"; | |||
constexpr char* background_bright_green = "\u003b[42;1m"; | |||
constexpr char* background_bright_yellow = "\u003b[43;1m"; | |||
constexpr char* background_bright_blue = "\u003b[44;1m"; | |||
constexpr char* background_bright_magenta = "\u003b[45;1m"; | |||
constexpr char* background_bright_cyan = "\u003b[46;1m"; | |||
constexpr char* background_bright_white = "\u003b[47;1m"; | |||
constexpr char* bold = "\u003b[1m"; | |||
constexpr char* underline = "\u003b[4m"; | |||
constexpr char* reversed = "\u001b[7m"; | |||
} // namespace ansi | |||
} // namespace debug | |||
#endif // ANTKEEPER_DEBUG_ANSI_CODES_HPP | |||
@ -1,56 +0,0 @@ | |||
/* | |||
* Copyright (C) 2023 Christopher J. Howard | |||
* | |||
* This file is part of Antkeeper source code. | |||
* | |||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation, either version 3 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* Antkeeper source code is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License | |||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | |||
#include "console-commands.hpp" | |||
#include "application.hpp" | |||
#include "animation/timeline.hpp" | |||
#include "debug/cli.hpp" | |||
namespace debug { | |||
namespace cc { | |||
std::string echo(std::string text) | |||
{ | |||
return text; | |||
} | |||
std::string exit(game::context* ctx) | |||
{ | |||
ctx->app->close(); | |||
return std::string(); | |||
} | |||
std::string scrot(game::context* ctx) | |||
{ | |||
//ctx->app->take_screenshot(); | |||
return std::string("screenshot saved"); | |||
} | |||
std::string cue(game::context* ctx, float t, std::string command) | |||
{ | |||
::timeline* timeline = ctx->timeline; | |||
debug::cli* cli = ctx->cli; | |||
timeline->add_cue({timeline->get_position() + t, std::function<void()>(std::bind(&debug::cli::interpret, cli, command))}); | |||
return std::string("command \"" + command + "\" will execute in " + std::to_string(t) + " seconds"); | |||
} | |||
} // namespace cc | |||
} // namespace debug |
@ -0,0 +1,51 @@ | |||
/* | |||
* Copyright (C) 2023 Christopher J. Howard | |||
* | |||
* This file is part of Antkeeper source code. | |||
* | |||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation, either version 3 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* Antkeeper source code is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License | |||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | |||
#include "debug/console.hpp" | |||
#if defined(_WIN32) | |||
#define WIN32_LEAN_AND_MEAN | |||
#include <windows.h> | |||
#endif | |||
namespace debug { | |||
namespace console { | |||
void enable_vt100() | |||
{ | |||
#if defined(_WIN32) | |||
DWORD mode = 0; | |||
HANDLE std_output_handle = GetStdHandle(STD_OUTPUT_HANDLE); | |||
GetConsoleMode(std_output_handle, &mode); | |||
SetConsoleMode(std_output_handle, mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING); | |||
#endif | |||
} | |||
void disable_vt100() | |||
{ | |||
#if defined(_WIN32) | |||
DWORD mode = 0; | |||
HANDLE std_output_handle = GetStdHandle(STD_OUTPUT_HANDLE); | |||
GetConsoleMode(std_output_handle, &mode); | |||
SetConsoleMode(std_output_handle, mode & (~ENABLE_VIRTUAL_TERMINAL_PROCESSING)); | |||
#endif | |||
} | |||
} // namespace console | |||
} // namespace debug |
@ -0,0 +1,39 @@ | |||
/* | |||
* Copyright (C) 2023 Christopher J. Howard | |||
* | |||
* This file is part of Antkeeper source code. | |||
* | |||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation, either version 3 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* Antkeeper source code is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License | |||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | |||
#ifndef ANTKEEPER_DEBUG_CONSOLE_HPP | |||
#define ANTKEEPER_DEBUG_CONSOLE_HPP | |||
namespace debug { | |||
/** | |||
* Debug console. | |||
*/ | |||
namespace console { | |||
/// Enables VT100 virtual terminal sequences. | |||
void enable_vt100(); | |||
/// Disables VT100 virtual terminal sequences. | |||
void disable_vt100(); | |||
} // namespace console | |||
} // namespace debug | |||
#endif // ANTKEEPER_DEBUG_CONSOLE_HPP |
@ -0,0 +1,58 @@ | |||
/* | |||
* Copyright (C) 2023 Christopher J. Howard | |||
* | |||
* This file is part of Antkeeper source code. | |||
* | |||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation, either version 3 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* Antkeeper source code is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License | |||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | |||
#include "debug/log.hpp" | |||
namespace debug { | |||
namespace log { | |||
logger& default_logger() noexcept | |||
{ | |||
static logger instance; | |||
return instance; | |||
} | |||
void push_task(const std::string& description, std::source_location&& location) | |||
{ | |||
default_logger().log(description + " {", message_severity::info, std::forward<std::source_location>(location)); | |||
} | |||
void pop_task(int status, const std::string& description, std::source_location&& location) | |||
{ | |||
std::string message = "} => "; | |||
if (status == EXIT_SUCCESS) | |||
{ | |||
message += "success"; | |||
default_logger().log(std::move(message), message_severity::info, std::forward<std::source_location>(location)); | |||
} | |||
else | |||
{ | |||
message += "failure"; | |||
if (!description.empty()) | |||
{ | |||
message += "(" + description + ")"; | |||
} | |||
default_logger().log(std::move(message), message_severity::error, std::forward<std::source_location>(location)); | |||
} | |||
} | |||
} // namespace log | |||
} // namespace debug |
@ -0,0 +1,189 @@ | |||
/* | |||
* Copyright (C) 2023 Christopher J. Howard | |||
* | |||
* This file is part of Antkeeper source code. | |||
* | |||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation, either version 3 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* Antkeeper source code is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License | |||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | |||
#ifndef ANTKEEPER_DEBUG_LOG_HPP | |||
#define ANTKEEPER_DEBUG_LOG_HPP | |||
#include "config.hpp" | |||
#include "debug/log/message-severity.hpp" | |||
#include "debug/log/logger.hpp" | |||
#include <source_location> | |||
#include <string> | |||
#include <format> | |||
// Enable logging of messages of all severities by default. | |||
#if !defined(ANTKEEPER_DEBUG_LOG_MIN_MESSAGE_SEVERITY) | |||
#define ANTKEEPER_DEBUG_LOG_MIN_MESSAGE_SEVERITY (ANTKEEPER_DEBUG_LOG_MESSAGE_SEVERITY_TRACE) | |||
#endif | |||
namespace debug { | |||
/** | |||
* Debug message logging. | |||
*/ | |||
namespace log { | |||
/** | |||
* Returns the default logger. | |||
*/ | |||
[[nodiscard]] logger& default_logger() noexcept; | |||
/** | |||
* Self-formatting message that logs itself to the default logger on construction. | |||
* | |||
* @tparam Severity Message severity. A message will not log itself if @p Severity is less than the user-defined macro `ANTKEEPER_DEBUG_LOG_MIN_MESSAGE_SEVERITY`. | |||
* @tparam Args Types of arguments to be formatted. | |||
*/ | |||
template <message_severity Severity, class... Args> | |||
struct message | |||
{ | |||
/** | |||
* Formats and logs a message. | |||
* | |||
* Class template argument deduction (CTAD) is utilized to capture source location as a default argument following variadic format arguments. | |||
* | |||
* @param format Message format string. | |||
* @param args Arguments to be formatted. | |||
* @param location Source location from which the message was sent. | |||
*/ | |||
message | |||
( | |||
[[maybe_unused]] std::string_view format, | |||
[[maybe_unused]] Args&&... args, | |||
[[maybe_unused]] std::source_location&& location = std::source_location::current() | |||
) | |||
{ | |||
if constexpr (ANTKEEPER_DEBUG_LOG_MIN_MESSAGE_SEVERITY <= static_cast<std::underlying_type_t<message_severity>>(Severity)) | |||
{ | |||
default_logger().log(std::vformat(format, std::make_format_args(std::forward<Args>(args)...)), Severity, std::forward<std::source_location>(location)); | |||
} | |||
} | |||
}; | |||
// Use class template argument deduction (CTAD) to capture source location as a default argument following variadic format arguments. | |||
template <message_severity Severity, class... Args> | |||
message(std::string_view, Args&&...) -> message<Severity, Args...>; | |||
#if (ANTKEEPER_DEBUG_LOG_MIN_MESSAGE_SEVERITY <= ANTKEEPER_DEBUG_LOG_MESSAGE_SEVERITY_TRACE) | |||
/** | |||
* Formats and logs a trace message. | |||
* | |||
* @param Args Types of arguments to be formatted. | |||
*/ | |||
template <class... Args> | |||
using trace = message<message_severity::trace, Args...>; | |||
#else | |||
// Disable trace message logging. | |||
inline void trace([[maybe_unused]] ...) noexcept {}; | |||
#endif | |||
#if (ANTKEEPER_DEBUG_LOG_MIN_MESSAGE_SEVERITY <= ANTKEEPER_DEBUG_LOG_MESSAGE_SEVERITY_DEBUG) | |||
/** | |||
* Formats and logs a debug message. | |||
* | |||
* @param Args Types of arguments to be formatted. | |||
*/ | |||
template <class... Args> | |||
using debug = message<message_severity::debug, Args...>; | |||
#else | |||
// Disable debug message logging. | |||
inline void debug([[maybe_unused]] ...) noexcept {}; | |||
#endif | |||
#if (ANTKEEPER_DEBUG_LOG_MIN_MESSAGE_SEVERITY <= ANTKEEPER_DEBUG_LOG_MESSAGE_SEVERITY_INFO) | |||
/** | |||
* Formats and logs an info message. | |||
* | |||
* @param Args Types of arguments to be formatted. | |||
*/ | |||
template <class... Args> | |||
using info = message<message_severity::info, Args...>; | |||
#else | |||
// Disable info message logging. | |||
inline void info([[maybe_unused]] ...) noexcept {}; | |||
#endif | |||
#if (ANTKEEPER_DEBUG_LOG_MIN_MESSAGE_SEVERITY <= ANTKEEPER_DEBUG_LOG_MESSAGE_SEVERITY_WARNING) | |||
/** | |||
* Formats and logs a warning message. | |||
* | |||
* @param Args Types of arguments to be formatted. | |||
*/ | |||
template <class... Args> | |||
using warning = message<message_severity::warning, Args...>; | |||
#else | |||
// Disable warning message logging. | |||
inline void warning([[maybe_unused]] ...) noexcept {}; | |||
#endif | |||
#if (ANTKEEPER_DEBUG_LOG_MIN_MESSAGE_SEVERITY <= ANTKEEPER_DEBUG_LOG_MESSAGE_SEVERITY_ERROR) | |||
/** | |||
* Formats and logs an error message. | |||
* | |||
* @param Args Types of arguments to be formatted. | |||
*/ | |||
template <class... Args> | |||
using error = message<message_severity::error, Args...>; | |||
#else | |||
// Disable error message logging. | |||
inline void error([[maybe_unused]] ...) noexcept {}; | |||
#endif | |||
#if (ANTKEEPER_DEBUG_LOG_MIN_MESSAGE_SEVERITY <= ANTKEEPER_DEBUG_LOG_MESSAGE_SEVERITY_FATAL) | |||
/** | |||
* Formats and logs a fatal error message. | |||
* | |||
* @param Args Types of arguments to be formatted. | |||
*/ | |||
template <class... Args> | |||
using fatal = message<message_severity::fatal, Args...>; | |||
#else | |||
// Disable fatal error message logging. | |||
inline void fatal([[maybe_unused]] ...) noexcept {}; | |||
#endif | |||
/** | |||
* Pushes a task onto the default logger's task stack and writes its description the log. | |||
* | |||
* @param description Task description. | |||
* @param location Source location from which the message was sent. | |||
*/ | |||
void push_task | |||
( | |||
const std::string& description, | |||
std::source_location&& location = std::source_location::current() | |||
); | |||
/** | |||
* Pops a task off the default logger's task stack and writes its status to the log. | |||
* | |||
* @param status Exit status of the task. A value of `0` or `EXIT_SUCCESS` indicates the task exited successfully. A non-zero exit status indicates the task failed. | |||
* @param description Error code description. | |||
*/ | |||
void pop_task | |||
( | |||
int status, | |||
const std::string& description = std::string(), | |||
std::source_location&& location = std::source_location::current() | |||
); | |||
} // namespace log | |||
} // namespace debug | |||
#endif // ANTKEEPER_DEBUG_LOG_HPP |
@ -0,0 +1,67 @@ | |||
/* | |||
* Copyright (C) 2023 Christopher J. Howard | |||
* | |||
* This file is part of Antkeeper source code. | |||
* | |||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation, either version 3 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* Antkeeper source code is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License | |||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | |||
#ifndef ANTKEEPER_DEBUG_LOG_EVENT_HPP | |||
#define ANTKEEPER_DEBUG_LOG_EVENT_HPP | |||
#include "debug/log/message-severity.hpp" | |||
#include <chrono> | |||
#include <source_location> | |||
#include <string> | |||
#include <thread> | |||
namespace debug { | |||
namespace log { | |||
class logger; | |||
/** | |||
* Debug logging events. | |||
*/ | |||
namespace event { | |||
/** | |||
* Event generated when a message has been logged. | |||
*/ | |||
struct message_logged | |||
{ | |||
/// Logger which received the message. | |||
log::logger* logger; | |||
/// Time at which the message was sent. | |||
std::chrono::time_point<std::chrono::system_clock> time; | |||
/// ID of the thread from which the message was sent. | |||
std::thread::id thread_id; | |||
/// Source location from which the message was sent. | |||
std::source_location location; | |||
/// Severity of the message. | |||
message_severity severity; | |||
/// Message contents. | |||
std::string message; | |||
}; | |||
} // namespace event | |||
} // namespace log | |||
} // namespace debug | |||
#endif // ANTKEEPER_DEBUG_LOG_EVENT_HPP |
@ -0,0 +1,65 @@ | |||
/* | |||
* Copyright (C) 2023 Christopher J. Howard | |||
* | |||
* This file is part of Antkeeper source code. | |||
* | |||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation, either version 3 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* Antkeeper source code is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License | |||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | |||
#ifndef ANTKEEPER_DEBUG_LOG_LOGGER_HPP | |||
#define ANTKEEPER_DEBUG_LOG_LOGGER_HPP | |||
#include "debug/log/message-severity.hpp" | |||
#include "debug/log/event.hpp" | |||
#include "event/publisher.hpp" | |||
#include <source_location> | |||
#include <string> | |||
namespace debug { | |||
namespace log { | |||
/** | |||
* Generates an event each time a message logged. | |||
*/ | |||
class logger | |||
{ | |||
public: | |||
/** | |||
* Logs a message. | |||
* | |||
* @param message Message contents. | |||
* @param severity Message severity. | |||
* @param location Source location from which the message was sent. | |||
*/ | |||
void log | |||
( | |||
std::string&& message, | |||
message_severity severity = message_severity::info, | |||
std::source_location&& location = std::source_location::current() | |||
); | |||
/// Returns the channel through which message logged events are published. | |||
[[nodiscard]] inline ::event::channel<event::message_logged>& get_message_logged_channel() noexcept | |||
{ | |||
return message_logged_publisher.channel(); | |||
} | |||
private: | |||
::event::publisher<event::message_logged> message_logged_publisher; | |||
}; | |||
} // namespace log | |||
} // namespace debug | |||
#endif // ANTKEEPER_DEBUG_LOG_LOGGER_HPP |
@ -0,0 +1,71 @@ | |||
/* | |||
* Copyright (C) 2023 Christopher J. Howard | |||
* | |||
* This file is part of Antkeeper source code. | |||
* | |||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation, either version 3 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* Antkeeper source code is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License | |||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | |||
#ifndef ANTKEEPER_DEBUG_LOG_MESSAGE_SEVERITY_HPP | |||
#define ANTKEEPER_DEBUG_LOG_MESSAGE_SEVERITY_HPP | |||
#include <cstdint> | |||
/// Trace message severity level. | |||
#define ANTKEEPER_DEBUG_LOG_MESSAGE_SEVERITY_TRACE 0 | |||
/// Debug message severity level. | |||
#define ANTKEEPER_DEBUG_LOG_MESSAGE_SEVERITY_DEBUG 1 | |||
/// Info message severity level. | |||
#define ANTKEEPER_DEBUG_LOG_MESSAGE_SEVERITY_INFO 2 | |||
/// Warning message severity level. | |||
#define ANTKEEPER_DEBUG_LOG_MESSAGE_SEVERITY_WARNING 3 | |||
/// Error message severity level. | |||
#define ANTKEEPER_DEBUG_LOG_MESSAGE_SEVERITY_ERROR 4 | |||
/// Fatal error message severity level. | |||
#define ANTKEEPER_DEBUG_LOG_MESSAGE_SEVERITY_FATAL 5 | |||
namespace debug { | |||
namespace log { | |||
/// Log message severity levels. | |||
enum class message_severity: std::uint8_t | |||
{ | |||
/// Trace message severity. | |||
trace = ANTKEEPER_DEBUG_LOG_MESSAGE_SEVERITY_TRACE, | |||
/// Debug message severity. | |||
debug = ANTKEEPER_DEBUG_LOG_MESSAGE_SEVERITY_DEBUG, | |||
/// Info message severity. | |||
info = ANTKEEPER_DEBUG_LOG_MESSAGE_SEVERITY_INFO, | |||
/// Warning message severity. | |||
warning = ANTKEEPER_DEBUG_LOG_MESSAGE_SEVERITY_WARNING, | |||
/// Error message severity. | |||
error = ANTKEEPER_DEBUG_LOG_MESSAGE_SEVERITY_ERROR, | |||
/// Fatal error message severity. | |||
fatal = ANTKEEPER_DEBUG_LOG_MESSAGE_SEVERITY_FATAL, | |||
}; | |||
} // namespace log | |||
} // namespace debug | |||
#endif // ANTKEEPER_DEBUG_LOG_MESSAGE_SEVERITY_HPP |
@ -1,230 +0,0 @@ | |||
/* | |||
* Copyright (C) 2023 Christopher J. Howard | |||
* | |||
* This file is part of Antkeeper source code. | |||
* | |||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation, either version 3 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* Antkeeper source code is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License | |||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | |||
#include "logger.hpp" | |||
#include "utility/timestamp.hpp" | |||
#include <iostream> | |||
#if defined(_WIN32) | |||
#define WIN32_LEAN_AND_MEAN | |||
#include <windows.h> | |||
#endif | |||
namespace debug { | |||
logger::logger(): | |||
os(&std::cout), | |||
auto_newline(true), | |||
timestamp_enabled(true), | |||
indent("| "), | |||
log_prefix(std::string()), | |||
log_postfix(std::string()), | |||
warning_prefix(std::string()), | |||
warning_postfix(std::string()), | |||
error_prefix(std::string()), | |||
error_postfix(std::string()), | |||
success_prefix(std::string()), | |||
success_postfix(std::string()) | |||
{} | |||
logger::~logger() | |||
{} | |||
void logger::redirect(std::ostream* stream) | |||
{ | |||
os = stream; | |||
} | |||
void logger::log(const std::string& text) | |||
{ | |||
if (os) | |||
{ | |||
std::string message = ""; | |||
// Prepend timestamp | |||
if (timestamp_enabled) | |||
{ | |||
message += timestamp(); | |||
message += ": "; | |||
} | |||
// Prepend indentation | |||
for (std::size_t i = 0; i < tasks.size(); ++i) | |||
message += indent; | |||
// Append text | |||
message += (log_prefix + text + log_postfix); | |||
// Append newline | |||
if (auto_newline) | |||
message += "\n"; | |||
// Add message to log history | |||
const std::lock_guard<std::mutex> history_lock(history_mutex); | |||
history += message; | |||
// Output message | |||
(*os) << message; | |||
// Flush output stream | |||
os->flush(); | |||
} | |||
} | |||
void logger::warning(const std::string& text) | |||
{ | |||
#if defined(_WIN32) | |||
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED | FOREGROUND_GREEN); | |||
#endif | |||
log(warning_prefix + text + warning_postfix); | |||
#if defined(_WIN32) | |||
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); | |||
#endif | |||
} | |||
void logger::error(const std::string& text) | |||
{ | |||
#if defined(_WIN32) | |||
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED); | |||
#endif | |||
log(error_prefix + text + error_postfix); | |||
#if defined(_WIN32) | |||
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); | |||
#endif | |||
} | |||
void logger::success(const std::string& text) | |||
{ | |||
/* | |||
#if defined(_WIN32) | |||
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_GREEN); | |||
#endif | |||
*/ | |||
log(success_prefix + text + success_postfix); | |||
/* | |||
#if defined(_WIN32) | |||
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE); | |||
#endif | |||
*/ | |||
} | |||
void logger::set_auto_newline(bool enabled) | |||
{ | |||
auto_newline = enabled; | |||
} | |||
void logger::set_timestamp(bool enabled) | |||
{ | |||
timestamp_enabled = enabled; | |||
} | |||
void logger::set_indent(const std::string& indent) | |||
{ | |||
this->indent = indent; | |||
} | |||
void logger::set_log_prefix(const std::string& prefix) | |||
{ | |||
log_prefix = prefix; | |||
} | |||
void logger::set_log_postfix(const std::string& postfix) | |||
{ | |||
log_postfix = postfix; | |||
} | |||
void logger::set_warning_prefix(const std::string& prefix) | |||
{ | |||
warning_prefix = prefix; | |||
} | |||
void logger::set_warning_postfix(const std::string& postfix) | |||
{ | |||
warning_postfix = postfix; | |||
} | |||
void logger::set_error_prefix(const std::string& prefix) | |||
{ | |||
error_prefix = prefix; | |||
} | |||
void logger::set_error_postfix(const std::string& postfix) | |||
{ | |||
error_postfix = postfix; | |||
} | |||
void logger::set_success_prefix(const std::string& prefix) | |||
{ | |||
success_prefix = prefix; | |||
} | |||
void logger::set_success_postfix(const std::string& postfix) | |||
{ | |||
success_postfix = postfix; | |||
} | |||
void logger::push_task(const std::string& description) | |||
{ | |||
std::string message = description + " {"; | |||
if (!auto_newline) | |||
message += "\n"; | |||
log(message); | |||
tasks.push(description); | |||
} | |||
void logger::pop_task(int status, std::string error) | |||
{ | |||
if (tasks.empty()) | |||
{ | |||
return; | |||
} | |||
std::string message = "} => "; | |||
tasks.pop(); | |||
if (status == EXIT_SUCCESS) | |||
{ | |||
message += "success"; | |||
if (!auto_newline) | |||
message += "\n"; | |||
success(message); | |||
} | |||
else | |||
{ | |||
message += "failure"; | |||
if (!error.empty()) | |||
message += " (" + error + ")"; | |||
if (!auto_newline) | |||
message += "\n"; | |||
this->error(message); | |||
} | |||
} | |||
} // namespace debug |
@ -1,130 +0,0 @@ | |||
/* | |||
* Copyright (C) 2023 Christopher J. Howard | |||
* | |||
* This file is part of Antkeeper source code. | |||
* | |||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation, either version 3 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* Antkeeper source code is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License | |||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | |||
#ifndef ANTKEEPER_DEBUG_LOGGER_HPP | |||
#define ANTKEEPER_DEBUG_LOGGER_HPP | |||
#include <list> | |||
#include <ostream> | |||
#include <stack> | |||
#include <string> | |||
#include <mutex> | |||
namespace debug { | |||
/** | |||
* Logs formatted debug messages to an output stream. | |||
*/ | |||
class logger | |||
{ | |||
public: | |||
/// Creates a logger. | |||
logger(); | |||
/// Destroys a logger. | |||
~logger(); | |||
/** | |||
* Redirects log output to the specified output stream. | |||
* | |||
* @param stream Output stream to which log text will be written. | |||
*/ | |||
void redirect(std::ostream* stream); | |||
/** | |||
* Outputs text to the log. | |||
*/ | |||
void log(const std::string& text); | |||
void warning(const std::string& text); | |||
void error(const std::string& text); | |||
void success(const std::string& text); | |||
/** | |||
* Enables or disables automatic appending of newlines to log messages. | |||
* | |||
* @param enabled `true` if auto newline should be enabled, `false` otherwise. | |||
*/ | |||
void set_auto_newline(bool enabled); | |||
/** | |||
* Enables or disables prefixing log messages with a timestamp. | |||
* | |||
* @param enabled `true` if timestamps should be enabled, `false` otherwise. | |||
*/ | |||
void set_timestamp(bool enabled); | |||
/** | |||
* Sets the indent string which prefixes subtasks. This string will be repeated according to the level of indentation. | |||
* | |||
* @param indent Indent string. | |||
*/ | |||
void set_indent(const std::string& indent); | |||
void set_log_prefix(const std::string& prefix); | |||
void set_log_postfix(const std::string& postfix); | |||
void set_warning_prefix(const std::string& prefix); | |||
void set_warning_postfix(const std::string& postfix); | |||
void set_error_prefix(const std::string& prefix); | |||
void set_error_postfix(const std::string& postfix); | |||
void set_success_prefix(const std::string& prefix); | |||
void set_success_postfix(const std::string& postfix); | |||
/** | |||
* Pushes a task onto the stack and outputs it to the log. | |||
* | |||
* @param description Task description. | |||
*/ | |||
void push_task(const std::string& description); | |||
/** | |||
* Pops a task off the stack and outputs its status to the log. | |||
* | |||
* @param status Exit status of the task. A value of `0` or `EXIT_SUCCESS` indicates the task exited successfully. A non-zero exit status indicates the task failed. | |||
*/ | |||
void pop_task(int status, std::string error = std::string()); | |||
const std::string& get_history() const; | |||
private: | |||
std::ostream* os; | |||
bool auto_newline; | |||
bool timestamp_enabled; | |||
std::string indent; | |||
std::string log_prefix; | |||
std::string log_postfix; | |||
std::string warning_prefix; | |||
std::string warning_postfix; | |||
std::string error_prefix; | |||
std::string error_postfix; | |||
std::string success_prefix; | |||
std::string success_postfix; | |||
std::stack<std::string> tasks; | |||
std::string history; | |||
std::mutex history_mutex; | |||
}; | |||
inline const std::string& logger::get_history() const | |||
{ | |||
return history; | |||
} | |||
} // namespace debug | |||
#endif // ANTKEEPER_DEBUG_LOGGER_HPP | |||
@ -0,0 +1,104 @@ | |||
/* | |||
* Copyright (C) 2023 Christopher J. Howard | |||
* | |||
* This file is part of Antkeeper source code. | |||
* | |||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation, either version 3 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* Antkeeper source code is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License | |||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | |||
#ifndef ANTKEEPER_EVENT_CHANNEL_HPP | |||
#define ANTKEEPER_EVENT_CHANNEL_HPP | |||
#include <functional> | |||
#include <list> | |||
#include <memory> | |||
#include <utility> | |||
#include "event/subscriber.hpp" | |||
#include "event/subscription.hpp" | |||
#include "event/queue.hpp" | |||
namespace event { | |||
template <class T> | |||
class publisher; | |||
/** | |||
* Channel through which messages are published. | |||
* | |||
* @tparam T Message type. | |||
*/ | |||
template <class T> | |||
class channel | |||
{ | |||
public: | |||
/// Message type. | |||
typedef T message_type; | |||
/// Subscriber function object type. | |||
typedef subscriber<message_type> subscriber_type; | |||
/** | |||
* Subscribes a function object to messages published through this channel. | |||
* | |||
* @param subscriber Subscriber function object which will received published messages. | |||
* | |||
* @return Shared subscription object which will unsubscribe the subscriber on destruction. | |||
*/ | |||
[[nodiscard]] std::shared_ptr<subscription> subscribe(subscriber_type&& subscriber) | |||
{ | |||
// Construct shared pointer to subscriber function | |||
std::shared_ptr<subscriber_type> shared_subscriber = std::make_shared<subscriber_type>(std::move(subscriber)); | |||
// Append subscriber to subscriber list and store iterator | |||
auto iterator = subscribers.insert(subscribers.end(), shared_subscriber); | |||
// Construct and return a shared subscription object which removes the subscriber from the subscriber list when unsubscribed or destructed | |||
return std::make_shared<subscription> | |||
( | |||
std::static_pointer_cast<void>(shared_subscriber), | |||
[this, iterator = std::move(iterator)] | |||
{ | |||
this->subscribers.erase(iterator); | |||
} | |||
); | |||
} | |||
/** | |||
* Subscribes a message queue to messages published through this channel. | |||
* | |||
* @param queue Message queue which will received published messages. | |||
* | |||
* @return Shared subscription object which will unsubscribe the queue on destruction. | |||
*/ | |||
[[nodiscard]] std::shared_ptr<subscription> subscribe(event::queue& queue) | |||
{ | |||
return subscribe | |||
( | |||
[&queue](const message_type& message) | |||
{ | |||
queue.enqueue<message_type>(message); | |||
} | |||
); | |||
} | |||
private: | |||
friend class publisher<T>; | |||
/// List of subscribers. | |||
std::list<std::shared_ptr<subscriber_type>> subscribers; | |||
}; | |||
} // namespace event | |||
#endif // ANTKEEPER_EVENT_CHANNEL_HPP |
@ -1,125 +0,0 @@ | |||
/* | |||
* Copyright (C) 2023 Christopher J. Howard | |||
* | |||
* This file is part of Antkeeper source code. | |||
* | |||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation, either version 3 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* Antkeeper source code is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License | |||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | |||
#include "event-dispatcher.hpp" | |||
event_dispatcher::event_dispatcher(): | |||
updating(false) | |||
{} | |||
event_dispatcher::~event_dispatcher() | |||
{ | |||
clear(); | |||
} | |||
void event_dispatcher::update(double time) | |||
{ | |||
updating = true; | |||
// Process pending subscriptions | |||
for (auto it = to_subscribe.begin(); it != to_subscribe.end(); ++it) | |||
{ | |||
handler_map[std::get<0>(*it)].push_back(std::get<1>(*it)); | |||
} | |||
to_subscribe.clear(); | |||
// Process pending unsubscriptions | |||
for (auto it = to_unsubscribe.begin(); it != to_unsubscribe.end(); ++it) | |||
{ | |||
handler_map[std::get<0>(*it)].remove(std::get<1>(*it)); | |||
} | |||
to_unsubscribe.clear(); | |||
// Dispatch queued events | |||
flush(); | |||
// For each scheduled event | |||
for (auto event = scheduled_events.begin(); event != scheduled_events.end();) | |||
{ | |||
// If the event is due | |||
if (time >= event->first) | |||
{ | |||
// Dispatch event | |||
dispatch(*(event->second)); | |||
// Delete event | |||
delete event->second; | |||
event = scheduled_events.erase(event); | |||
} | |||
else | |||
{ | |||
break; | |||
} | |||
} | |||
updating = false; | |||
} | |||
void event_dispatcher::dispatch(const event_base& event) | |||
{ | |||
// Get list of handlers for this type of event | |||
const std::list<event_handler_base*>& handlers = handler_map[event.get_event_type_id()]; | |||
// For each handler | |||
for (auto handler = handlers.begin(); handler != handlers.end(); ++handler) | |||
{ | |||
// Pass event to the handler | |||
(*handler)->route_event(event); | |||
} | |||
} | |||
void event_dispatcher::flush() | |||
{ | |||
// For each event in the queue | |||
for (auto event = queued_events.begin(); event != queued_events.end(); ++event) | |||
{ | |||
// Dispatch event | |||
dispatch(**event); | |||
// Delete event | |||
delete (*event); | |||
} | |||
// Clear event queue | |||
queued_events.clear(); | |||
} | |||
void event_dispatcher::clear() | |||
{ | |||
// For each event in the queue | |||
for (auto event = queued_events.begin(); event != queued_events.end(); ++event) | |||
{ | |||
// Delete event | |||
delete (*event); | |||
} | |||
// Clear event queue | |||
queued_events.clear(); | |||
// For each scheduled event | |||
for (auto event = scheduled_events.begin(); event != scheduled_events.end(); ++event) | |||
{ | |||
// Delete event | |||
delete event->second; | |||
} | |||
// Clear scheduled events | |||
scheduled_events.clear(); | |||
} | |||
@ -1,140 +0,0 @@ | |||
/* | |||
* Copyright (C) 2023 Christopher J. Howard | |||
* | |||
* This file is part of Antkeeper source code. | |||
* | |||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation, either version 3 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* Antkeeper source code is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License | |||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | |||
#ifndef ANTKEEPER_EVENT_DISPATCHER_HPP | |||
#define ANTKEEPER_EVENT_DISPATCHER_HPP | |||
#include "event.hpp" | |||
#include "event-handler.hpp" | |||
#include <cstddef> | |||
#include <list> | |||
#include <map> | |||
/** | |||
* Queues events and dispatches them to event handlers. | |||
*/ | |||
class event_dispatcher | |||
{ | |||
public: | |||
/// Creates an event dispatcher | |||
event_dispatcher(); | |||
/// Destroys an event dispatcher | |||
~event_dispatcher(); | |||
/** | |||
* Processes all pending subscriptions and unsubscriptions, dispatches queued events, then dispatches due scheduled events. | |||
* | |||
* @param time The current time. | |||
*/ | |||
void update(double time); | |||
/** | |||
* Subscribes an event handler to event dispatches. | |||
* | |||
* @param handler Handler to subscribe. | |||
*/ | |||
template <typename T> | |||
void subscribe(event_handler<T>* handler); | |||
/** | |||
* Unsubscribes an event handler from event dispatches. | |||
* | |||
* @param handler Handler to unsubscribe. | |||
*/ | |||
template <typename T> | |||
void unsubscribe(event_handler<T>* handler); | |||
/** | |||
* Adds an event to the queue. | |||
* | |||
* @param event Event to queue. | |||
*/ | |||
void queue(const event_base& event); | |||
/** | |||
* Schedules an event to be dispatched at a specific time. | |||
* | |||
* @param event Event to schedule. | |||
* @param time Time that the event should be dispatched. | |||
*/ | |||
void schedule(const event_base& event, double time); | |||
/** | |||
* Dispatches a single event. | |||
* | |||
* @param event Event to dispatch. | |||
*/ | |||
void dispatch(const event_base& event); | |||
/** | |||
* Dispatches all events in the queue. | |||
*/ | |||
void flush(); | |||
/// Removes all queued and scheduled events from the queue without notifying handlers. | |||
void clear(); | |||
private: | |||
std::list<std::tuple<std::size_t, event_handler_base*>> to_subscribe; | |||
std::list<std::tuple<std::size_t, event_handler_base*>> to_unsubscribe; | |||
std::map<std::size_t, std::list<event_handler_base*>> handler_map; | |||
std::list<event_base*> queued_events; | |||
std::multimap<double, event_base*> scheduled_events; | |||
bool updating; | |||
}; | |||
template <typename T> | |||
void event_dispatcher::subscribe(event_handler<T>* handler) | |||
{ | |||
if (updating) | |||
{ | |||
to_subscribe.push_back(std::make_tuple(handler->get_handled_event_type_id(), handler)); | |||
} | |||
else | |||
{ | |||
handler_map[handler->get_handled_event_type_id()].push_back(handler); | |||
} | |||
} | |||
template <typename T> | |||
void event_dispatcher::unsubscribe(event_handler<T>* handler) | |||
{ | |||
if (updating) | |||
{ | |||
to_unsubscribe.push_back(std::make_tuple(handler->get_handled_event_type_id(), handler)); | |||
} | |||
else | |||
{ | |||
handler_map[handler->get_handled_event_type_id()].remove(handler); | |||
} | |||
} | |||
inline void event_dispatcher::queue(const event_base& event) | |||
{ | |||
queued_events.push_back(event.clone()); | |||
} | |||
inline void event_dispatcher::schedule(const event_base& event, double time) | |||
{ | |||
scheduled_events.insert(std::pair<double, event_base*>(time, event.clone())); | |||
} | |||
#endif // ANTKEEPER_EVENT_DISPATCHER_HPP | |||
@ -1,83 +0,0 @@ | |||
/* | |||
* Copyright (C) 2023 Christopher J. Howard | |||
* | |||
* This file is part of Antkeeper source code. | |||
* | |||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation, either version 3 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* Antkeeper source code is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License | |||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | |||
#ifndef ANTKEEPER_EVENT_HANDLER_HPP | |||
#define ANTKEEPER_EVENT_HANDLER_HPP | |||
#include "event.hpp" | |||
#include <type_traits> | |||
class event_dispatcher; | |||
/** | |||
* Abstract base class for event handlers. | |||
*/ | |||
class event_handler_base | |||
{ | |||
private: | |||
friend class event_dispatcher; | |||
/** | |||
* Receives an event, casts it to its derived event type, then handles it. | |||
* | |||
* @param event Received event. | |||
*/ | |||
virtual void route_event(const event_base& event) = 0; | |||
}; | |||
/** | |||
* Templates abstract base class for event handlers. | |||
* | |||
* @tparam Event type. | |||
*/ | |||
template <typename T> | |||
class event_handler: public event_handler_base | |||
{ | |||
public: | |||
static_assert(std::is_base_of<event_base, T>::value, "T must be a descendant of event_base."); | |||
/// Returns the unique event type identifier for the event type handled by this event handler. | |||
const std::size_t get_handled_event_type_id() const; | |||
/** | |||
* Handles an event of type T. | |||
* | |||
* @param event Event to handle. | |||
*/ | |||
virtual void handle_event(const T& event) = 0; | |||
private: | |||
/// @copydoc event_handler_base::route_event() | |||
virtual void route_event(const event_base& event) final; | |||
}; | |||
template <typename T> | |||
inline const std::size_t event_handler<T>::get_handled_event_type_id() const | |||
{ | |||
return T::event_type_id; | |||
} | |||
template <typename T> | |||
void event_handler<T>::route_event(const event_base& event) | |||
{ | |||
handle_event(static_cast<const T&>(event)); | |||
} | |||
#endif // ANTKEEPER_EVENT_HANDLER_HPP | |||
@ -1,88 +0,0 @@ | |||
/* | |||
* Copyright (C) 2023 Christopher J. Howard | |||
* | |||
* This file is part of Antkeeper source code. | |||
* | |||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation, either version 3 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* Antkeeper source code is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License | |||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | |||
#ifndef ANTKEEPER_EVENT_HPP | |||
#define ANTKEEPER_EVENT_HPP | |||
#include <atomic> | |||
#include <cstddef> | |||
/** | |||
* Abstract base class for events. | |||
*/ | |||
class event_base | |||
{ | |||
public: | |||
/// Destroys an event base. | |||
virtual ~event_base() = default; | |||
/// Returns the unique event type identifier for this event type. | |||
virtual const std::size_t get_event_type_id() const = 0; | |||
/** | |||
* Allocates a copy of this event. | |||
* | |||
* @return Newly allocated copy of this event. | |||
*/ | |||
virtual event_base* clone() const = 0; | |||
protected: | |||
/// Returns then increments the next available event type ID. | |||
static std::size_t next_event_type_id(); | |||
}; | |||
inline std::size_t event_base::next_event_type_id() | |||
{ | |||
static std::atomic<std::size_t> next_event_type_id{0}; | |||
return next_event_type_id++; | |||
} | |||
/** | |||
* Templated abstract base class for events. | |||
* | |||
* @tparam T The derived class. | |||
*/ | |||
template <typename T> | |||
class event: public event_base | |||
{ | |||
public: | |||
/// The unique event type identifier for this event type. | |||
static const std::atomic<std::size_t> event_type_id; | |||
/// Destroys an event | |||
virtual ~event() = default; | |||
/// @copydoc event_base::get_event_type_id() const | |||
virtual const std::size_t get_event_type_id() const final; | |||
/// @copydoc event_base::clone() const | |||
virtual event_base* clone() const = 0; | |||
}; | |||
template <typename T> | |||
const std::atomic<std::size_t> event<T>::event_type_id{event_base::next_event_type_id()}; | |||
template <typename T> | |||
inline const std::size_t event<T>::get_event_type_id() const | |||
{ | |||
return event_type_id; | |||
} | |||
#endif // ANTKEEPER_EVENT_HPP | |||
@ -1,117 +0,0 @@ | |||
/* | |||
* Copyright (C) 2023 Christopher J. Howard | |||
* | |||
* This file is part of Antkeeper source code. | |||
* | |||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation, either version 3 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* Antkeeper source code is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License | |||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | |||
#include "input-events.hpp" | |||
event_base* key_pressed_event::clone() const | |||
{ | |||
key_pressed_event* event = new key_pressed_event(); | |||
event->keyboard = keyboard; | |||
event->scancode = scancode; | |||
return event; | |||
} | |||
event_base* key_released_event::clone() const | |||
{ | |||
key_released_event* event = new key_released_event(); | |||
event->keyboard = keyboard; | |||
event->scancode = scancode; | |||
return event; | |||
} | |||
event_base* mouse_moved_event::clone() const | |||
{ | |||
mouse_moved_event* event = new mouse_moved_event(); | |||
event->mouse = mouse; | |||
event->x = x; | |||
event->y = y; | |||
event->dx = dx; | |||
event->dy = dy; | |||
return event; | |||
} | |||
event_base* mouse_button_pressed_event::clone() const | |||
{ | |||
mouse_button_pressed_event* event = new mouse_button_pressed_event(); | |||
event->mouse = mouse; | |||
event->button = button; | |||
event->x = x; | |||
event->y = y; | |||
return event; | |||
} | |||
event_base* mouse_button_released_event::clone() const | |||
{ | |||
mouse_button_released_event* event = new mouse_button_released_event(); | |||
event->mouse = mouse; | |||
event->button = button; | |||
event->x = x; | |||
event->y = y; | |||
return event; | |||
} | |||
event_base* mouse_wheel_scrolled_event::clone() const | |||
{ | |||
mouse_wheel_scrolled_event* event = new mouse_wheel_scrolled_event(); | |||
event->mouse = mouse; | |||
event->x = x; | |||
event->y = y; | |||
return event; | |||
} | |||
event_base* gamepad_connected_event::clone() const | |||
{ | |||
gamepad_connected_event* event = new gamepad_connected_event(); | |||
event->controller = controller; | |||
event->reconnected = reconnected; | |||
return event; | |||
} | |||
event_base* gamepad_disconnected_event::clone() const | |||
{ | |||
gamepad_disconnected_event* event = new gamepad_disconnected_event(); | |||
event->controller = controller; | |||
return event; | |||
} | |||
event_base* gamepad_button_pressed_event::clone() const | |||
{ | |||
gamepad_button_pressed_event* event = new gamepad_button_pressed_event(); | |||
event->controller = controller; | |||
event->button = button; | |||
return event; | |||
} | |||
event_base* gamepad_button_released_event::clone() const | |||
{ | |||
gamepad_button_released_event* event = new gamepad_button_released_event(); | |||
event->controller = controller; | |||
event->button = button; | |||
return event; | |||
} | |||
event_base* gamepad_axis_moved_event::clone() const | |||
{ | |||
gamepad_axis_moved_event* event = new gamepad_axis_moved_event(); | |||
event->controller = controller; | |||
event->axis = axis; | |||
event->value = value; | |||
return event; | |||
} | |||
@ -1,170 +0,0 @@ | |||
/* | |||
* Copyright (C) 2023 Christopher J. Howard | |||
* | |||
* This file is part of Antkeeper source code. | |||
* | |||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation, either version 3 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* Antkeeper source code is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License | |||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | |||
#ifndef ANTKEEPER_INPUT_EVENTS_HPP | |||
#define ANTKEEPER_INPUT_EVENTS_HPP | |||
#include "event/event.hpp" | |||
#include "input/scancode.hpp" | |||
#include "input/keyboard.hpp" | |||
#include "input/mouse.hpp" | |||
#include "input/gamepad.hpp" | |||
/** | |||
* Input event which indicates a keyboard key has been pressed. | |||
*/ | |||
class key_pressed_event: public event<key_pressed_event> | |||
{ | |||
public: | |||
virtual event_base* clone() const; | |||
input::keyboard* keyboard; | |||
input::scancode scancode; | |||
}; | |||
/** | |||
* Input event which indicates a keyboard key has been released. | |||
*/ | |||
class key_released_event: public event<key_released_event> | |||
{ | |||
public: | |||
virtual event_base* clone() const; | |||
input::keyboard* keyboard; | |||
input::scancode scancode; | |||
}; | |||
/** | |||
* Input event which indicates a mouse has been moved. | |||
*/ | |||
class mouse_moved_event: public event<mouse_moved_event> | |||
{ | |||
public: | |||
virtual event_base* clone() const; | |||
input::mouse* mouse; | |||
int x; | |||
int y; | |||
int dx; | |||
int dy; | |||
}; | |||
/** | |||
* Input event which indicates a mouse button has been pressed. | |||
*/ | |||
class mouse_button_pressed_event: public event<mouse_button_pressed_event> | |||
{ | |||
public: | |||
virtual event_base* clone() const; | |||
input::mouse* mouse; | |||
int button; | |||
int x; | |||
int y; | |||
}; | |||
/** | |||
* Input event which indicates a mouse button has been released. | |||
*/ | |||
class mouse_button_released_event: public event<mouse_button_released_event> | |||
{ | |||
public: | |||
virtual event_base* clone() const; | |||
input::mouse* mouse; | |||
int button; | |||
int x; | |||
int y; | |||
}; | |||
/** | |||
* Input event which indicates a mouse wheel has been scrolled. | |||
*/ | |||
class mouse_wheel_scrolled_event: public event<mouse_wheel_scrolled_event> | |||
{ | |||
public: | |||
virtual event_base* clone() const; | |||
input::mouse* mouse; | |||
int x; | |||
int y; | |||
}; | |||
/** | |||
* Input event which indicates a controller has been connected. | |||
*/ | |||
class gamepad_connected_event: public event<gamepad_connected_event> | |||
{ | |||
public: | |||
virtual event_base* clone() const; | |||
input::gamepad* controller; | |||
bool reconnected; | |||
}; | |||
/** | |||
* Input event which indicates a controller has been disconnected. | |||
*/ | |||
class gamepad_disconnected_event: public event<gamepad_disconnected_event> | |||
{ | |||
public: | |||
virtual event_base* clone() const; | |||
input::gamepad* controller; | |||
}; | |||
/** | |||
* Input event which indicates a controller button has been pressed. | |||
*/ | |||
class gamepad_button_pressed_event: public event<gamepad_button_pressed_event> | |||
{ | |||
public: | |||
virtual event_base* clone() const; | |||
input::gamepad* controller; | |||
input::gamepad_button button; | |||
}; | |||
/** | |||
* Input event which indicates a controller button has been released. | |||
*/ | |||
class gamepad_button_released_event: public event<gamepad_button_released_event> | |||
{ | |||
public: | |||
virtual event_base* clone() const; | |||
input::gamepad* controller; | |||
input::gamepad_button button; | |||
}; | |||
/** | |||
* Input event which indicates a controller axis has been moved. | |||
*/ | |||
class gamepad_axis_moved_event: public event<gamepad_axis_moved_event> | |||
{ | |||
public: | |||
virtual event_base* clone() const; | |||
input::gamepad* controller; | |||
input::gamepad_axis axis; | |||
float value; | |||
}; | |||
#endif // ANTKEEPER_INPUT_EVENTS_HPP | |||
@ -0,0 +1,95 @@ | |||
/* | |||
* Copyright (C) 2023 Christopher J. Howard | |||
* | |||
* This file is part of Antkeeper source code. | |||
* | |||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation, either version 3 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* Antkeeper source code is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License | |||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | |||
#ifndef ANTKEEPER_EVENT_PUBLISHER_HPP | |||
#define ANTKEEPER_EVENT_PUBLISHER_HPP | |||
#include <algorithm> | |||
#include <execution> | |||
#include "event/channel.hpp" | |||
namespace event { | |||
/** | |||
* Publishes messages to subscribers. | |||
* | |||
* @tparam T Message type. | |||
*/ | |||
template <class T> | |||
class publisher | |||
{ | |||
public: | |||
/// Message type. | |||
typedef T message_type; | |||
/// Channel type. | |||
typedef channel<message_type> channel_type; | |||
/** | |||
* Publishes a message. | |||
* | |||
* @tparam ExecutionPolicy Execution policy type. | |||
* | |||
* @param policy Execution policy to use. | |||
* @param message Message to publish. | |||
*/ | |||
/// @{ | |||
template <class ExecutionPolicy> | |||
void publish(ExecutionPolicy&& policy, const message_type& message) const | |||
{ | |||
std::for_each | |||
( | |||
policy, | |||
std::begin(m_channel.subscribers), | |||
std::end(m_channel.subscribers), | |||
[&](const auto& subscriber) | |||
{ | |||
(*subscriber)(message); | |||
} | |||
); | |||
} | |||
void publish(const message_type& message) const | |||
{ | |||
publish(std::execution::seq, message); | |||
} | |||
/// @} | |||
/** | |||
* Returns the channel through which messages are published. | |||
*/ | |||
/// @{ | |||
[[nodiscard]] inline const channel_type& channel() const noexcept | |||
{ | |||
return m_channel; | |||
} | |||
[[nodiscard]] inline channel_type& channel() noexcept | |||
{ | |||
return m_channel; | |||
} | |||
/// @} | |||
private: | |||
channel_type m_channel; | |||
}; | |||
} // namespace event | |||
#endif // ANTKEEPER_EVENT_PUBLISHER_HPP |
@ -0,0 +1,143 @@ | |||
/* | |||
* Copyright (C) 2023 Christopher J. Howard | |||
* | |||
* This file is part of Antkeeper source code. | |||
* | |||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation, either version 3 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* Antkeeper source code is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License | |||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | |||
#ifndef ANTKEEPER_EVENT_QUEUE_HPP | |||
#define ANTKEEPER_EVENT_QUEUE_HPP | |||
#include <any> | |||
#include <functional> | |||
#include <list> | |||
#include <map> | |||
#include <memory> | |||
#include <utility> | |||
#include "event/subscriber.hpp" | |||
#include "event/subscription.hpp" | |||
#include "utility/type-id.hpp" | |||
namespace event { | |||
/** | |||
* Collects messages from publishers to be distributed to subscribers when desired. | |||
*/ | |||
class queue | |||
{ | |||
public: | |||
/** | |||
* Subscribes a function object to messages published by this queue. | |||
* | |||
* @tparam T Message type. | |||
* | |||
* @param subscriber Function object to subscribe. | |||
* | |||
* @return Shared subscription object which will unsubscribe the subscriber on destruction. | |||
*/ | |||
template <class T> | |||
[[nodiscard]] std::shared_ptr<subscription> subscribe(subscriber<T>&& subscriber) | |||
{ | |||
// Allocate shared pointer to std::any object containing subscriber | |||
std::shared_ptr<std::any> shared_subscriber = std::make_shared<std::any>(std::make_any<event::subscriber<T>>(std::move(subscriber))); | |||
// Append subscriber to subscriber list and store iterator | |||
auto iterator = subscribers.emplace(type_id<T>, shared_subscriber); | |||
// Construct and return a shared subscription object which removes the subscriber from the subscriber list when unsubscribed or destructed | |||
return std::make_shared<subscription> | |||
( | |||
std::static_pointer_cast<void>(shared_subscriber), | |||
[this, iterator = std::move(iterator)]() | |||
{ | |||
this->subscribers.erase(iterator); | |||
} | |||
); | |||
} | |||
/** | |||
* Adds a message to the queue, to be distributed later. | |||
* | |||
* @tparam T Message type. | |||
* | |||
* @param message Message to enqueue. | |||
*/ | |||
template <class T> | |||
void enqueue(const T& message) | |||
{ | |||
messages.emplace_back | |||
( | |||
[this, message]() | |||
{ | |||
this->distribute<T>(message); | |||
} | |||
); | |||
} | |||
/** | |||
* Distributes queued messages in FIFO order to subscribers. | |||
*/ | |||
void flush() | |||
{ | |||
while (!messages.empty()) | |||
{ | |||
messages.front()(); | |||
messages.pop_front(); | |||
} | |||
} | |||
/** | |||
* Removes all messages from the queue. | |||
*/ | |||
void clear() | |||
{ | |||
messages.clear(); | |||
} | |||
/** | |||
* Returns `true` if there are no messages in the queue, `false` otherwise. | |||
*/ | |||
[[nodiscard]] inline bool empty() const noexcept | |||
{ | |||
return messages.empty(); | |||
} | |||
private: | |||
/** | |||
* Distributes a message. | |||
* | |||
* @tparam T Message type. | |||
* | |||
* @param message Message to distribute. | |||
*/ | |||
template <class T> | |||
void distribute(const T& message) const | |||
{ | |||
// For each subscriber of the given message type | |||
const auto range = subscribers.equal_range(type_id<T>); | |||
for (auto i = range.first; i != range.second; ++i) | |||
{ | |||
// Send message to subscriber | |||
std::any_cast<subscriber<T>>(*(i->second))(message); | |||
} | |||
} | |||
std::multimap<type_id_t, std::shared_ptr<std::any>> subscribers; | |||
std::list<std::function<void()>> messages; | |||
}; | |||
} // namespace event | |||
#endif // ANTKEEPER_EVENT_QUEUE_HPP |
@ -1,262 +0,0 @@ | |||
/* | |||
* Copyright (C) 2023 Christopher J. Howard | |||
* | |||
* This file is part of Antkeeper source code. | |||
* | |||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation, either version 3 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* Antkeeper source code is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License | |||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | |||
#ifndef ANTKEEPER_EVENT_SIGNAL_HPP | |||
#define ANTKEEPER_EVENT_SIGNAL_HPP | |||
#include <algorithm> | |||
#include <execution> | |||
#include <functional> | |||
#include <list> | |||
#include <memory> | |||
#include <type_traits> | |||
//namespace event { | |||
template <class T> | |||
class signal; | |||
template <class T> | |||
class connector; | |||
/** | |||
* Manages a connection between a signal and handler. A signal will be disconnected from a handler when the connection is destructed or is disconnected manually via connection::disconnect(). | |||
*/ | |||
class connection | |||
{ | |||
public: | |||
/// Signal handler disconnect function type. | |||
typedef std::function<void(std::weak_ptr<void>)> disconnector_type; | |||
/** | |||
* Constructs a connection between a signal and a handler. | |||
* | |||
* @param handler Weak pointer to a signal handler. | |||
* @param disconnector Signal handler disconnect function. | |||
*/ | |||
connection(std::weak_ptr<void> handler, disconnector_type disconnector); | |||
/** | |||
* Destructs a connection between a signal and a handler. | |||
*/ | |||
~connection(); | |||
/** | |||
* Returns `true` if the signal and handler are connected, `false` otherwise. | |||
*/ | |||
bool connected() const noexcept; | |||
/** | |||
* Disconnects the signal from the handler. | |||
*/ | |||
void disconnect(); | |||
private: | |||
template <class T> | |||
friend class signal; | |||
std::weak_ptr<void> handler; | |||
disconnector_type disconnector; | |||
}; | |||
/** | |||
* Creates connections between a signal and signal handlers. | |||
* | |||
* @tparam T Signal response type. | |||
* @tparam Args Signal argument types. | |||
*/ | |||
template <class T, class... Args> | |||
class connector<T(Args...)> | |||
{ | |||
public: | |||
/// Signal response type. | |||
typedef T response_type; | |||
/// Signal type. | |||
typedef signal<T(Args...)> signal_type; | |||
/** | |||
* Constructs a signal connector. | |||
* | |||
* @param signal Signal to which handlers may be connected. | |||
*/ | |||
connector(signal_type& signal): | |||
signal(&signal) | |||
{} | |||
/// @copydoc signal::connect(handler_type) | |||
std::shared_ptr<connection> connect(typename signal_type::handler_type handler) | |||
{ | |||
return signal->connect(handler); | |||
} | |||
private: | |||
signal_type* signal; | |||
}; | |||
/** | |||
* Emits signals to signal handlers. | |||
* | |||
* @tparam T Signal response type. | |||
* @tparam Args Signal argument types. | |||
*/ | |||
template <class T, class... Args> | |||
class signal<T(Args...)> | |||
{ | |||
public: | |||
/// Signal response type. | |||
typedef T response_type; | |||
/// Signal handler type. | |||
typedef std::function<T(Args...)> handler_type; | |||
/// Signal connector type. | |||
typedef connector<T(Args...)> connector_type; | |||
/** | |||
* Constructs a signal. | |||
*/ | |||
signal(): | |||
signal_connector(*this) | |||
{} | |||
/** | |||
* Returns the connector for this signal. | |||
*/ | |||
connector_type& connector() noexcept | |||
{ | |||
return signal_connector; | |||
} | |||
/** | |||
* Connects the signal to a handler. | |||
* | |||
* @param handler Signal handler to connect. | |||
* | |||
* @return Connection between the signal and handler. | |||
*/ | |||
std::shared_ptr<connection> connect(handler_type handler) | |||
{ | |||
// Allocate shared pointer to handler | |||
std::shared_ptr<handler_type> shared_handler = std::make_shared<handler_type>(handler); | |||
// Add handler to list of connected handlers | |||
connections.push_back(shared_handler); | |||
// Return a shared pointer to the connection between the signal and handler | |||
return std::make_shared<connection> | |||
( | |||
std::static_pointer_cast<void>(shared_handler), | |||
[this](std::weak_ptr<void> handler) | |||
{ | |||
this->connections.remove(std::static_pointer_cast<handler_type>(handler.lock())); | |||
} | |||
); | |||
} | |||
/** | |||
* Disconnects the signal from all connected handlers. | |||
*/ | |||
void disconnect() | |||
{ | |||
connections.clear(); | |||
} | |||
/** | |||
* Emits a signal to all connected handlers. | |||
* | |||
* @tparam ExecutionPolicy Execution policy type. | |||
* | |||
* @param policy Execution policy to use. | |||
* @param args Signal arguments. | |||
*/ | |||
/// @{ | |||
template <class ExecutionPolicy> | |||
void emit(ExecutionPolicy&& policy, Args... args) const | |||
{ | |||
std::for_each | |||
( | |||
policy, | |||
std::begin(connections), | |||
std::end(connections), | |||
[&](const auto& handler) | |||
{ | |||
(*handler)(args...); | |||
} | |||
); | |||
} | |||
void emit(Args... args) const | |||
{ | |||
emit(std::execution::seq, args...); | |||
} | |||
/// @} | |||
/** | |||
* Emits a signal to all connected handlers and relays their responses to a listener. | |||
* | |||
* @tparam ExecutionPolicy Execution policy type. | |||
* @tparam UnaryFunction Listener function object type. | |||
* | |||
* @param policy Execution policy to use. | |||
* @param listener Listener function object. | |||
* @param args Signal arguments. | |||
*/ | |||
/// @{ | |||
template <class ExecutionPolicy, class UnaryFunction> | |||
void ping(ExecutionPolicy&& policy, UnaryFunction listener, Args... args) const | |||
{ | |||
std::for_each | |||
( | |||
policy, | |||
std::begin(connections), | |||
std::end(connections), | |||
[&](const auto& handler) | |||
{ | |||
if constexpr(std::is_void_v<T>) | |||
{ | |||
(*handler)(args...); | |||
listener(); | |||
} | |||
else | |||
{ | |||
listener((*handler)(args...)); | |||
} | |||
} | |||
); | |||
} | |||
template <class UnaryFunction> | |||
void ping(UnaryFunction listener, Args... args) const | |||
{ | |||
ping(std::execution::seq, listener, args...); | |||
} | |||
/// @} | |||
private: | |||
/// List of connected signal handlers. | |||
std::list<std::shared_ptr<handler_type>> connections; | |||
/// Signal connector. | |||
connector_type signal_connector; | |||
}; | |||
//} // namespace event | |||
#endif // ANTKEEPER_EVENT_SIGNAL_HPP |
@ -0,0 +1,48 @@ | |||
/* | |||
* Copyright (C) 2023 Christopher J. Howard | |||
* | |||
* This file is part of Antkeeper source code. | |||
* | |||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation, either version 3 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* Antkeeper source code is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License | |||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | |||
#include "event/subscription.hpp" | |||
#include <utility> | |||
namespace event { | |||
subscription::subscription(std::weak_ptr<void>&& subscriber, unsubscribe_type&& unsubscriber): | |||
subscriber(std::move(subscriber)), | |||
unsubscriber(std::move(unsubscriber)) | |||
{} | |||
subscription::~subscription() | |||
{ | |||
unsubscribe(); | |||
} | |||
bool subscription::expired() const noexcept | |||
{ | |||
return subscriber.expired(); | |||
} | |||
void subscription::unsubscribe() | |||
{ | |||
if (!expired()) | |||
{ | |||
unsubscriber(); | |||
} | |||
} | |||
} // namespace event |
@ -0,0 +1,67 @@ | |||
/* | |||
* Copyright (C) 2023 Christopher J. Howard | |||
* | |||
* This file is part of Antkeeper source code. | |||
* | |||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation, either version 3 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* Antkeeper source code is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License | |||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | |||
#ifndef ANTKEEPER_EVENT_SUBSCRIPTION_HPP | |||
#define ANTKEEPER_EVENT_SUBSCRIPTION_HPP | |||
#include <functional> | |||
#include <memory> | |||
namespace event { | |||
/** | |||
* Subscription object which unsubscribes on destruction. | |||
*/ | |||
class subscription | |||
{ | |||
public: | |||
/// Unsubscribe function object type. | |||
typedef std::function<void()> unsubscribe_type; | |||
/** | |||
* Constructs a subscription. | |||
* | |||
* @param subscriber Weak pointer to the subscriber. | |||
* @param unsubscriber Unsubscribe function object. | |||
*/ | |||
subscription(std::weak_ptr<void>&& subscriber, unsubscribe_type&& unsubscriber); | |||
/** | |||
* Unsubscribes the subscriber and destructs the subscription. | |||
*/ | |||
~subscription(); | |||
/** | |||
* Returns `true` if the subscription is no longer active, `false` otherwise. | |||
*/ | |||
[[nodiscard]] bool expired() const noexcept; | |||
/** | |||
* Unsubscribes the subscriber. | |||
*/ | |||
void unsubscribe(); | |||
private: | |||
std::weak_ptr<void> subscriber; | |||
unsubscribe_type unsubscriber; | |||
}; | |||
} // namespace event | |||
#endif // ANTKEEPER_EVENT_SUBSCRIPTION_HPP |
@ -0,0 +1,299 @@ | |||
/* | |||
* Copyright (C) 2023 Christopher J. Howard | |||
* | |||
* This file is part of Antkeeper source code. | |||
* | |||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation, either version 3 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* Antkeeper source code is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License | |||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | |||
#include "input/control-map.hpp" | |||
#include <algorithm> | |||
#include <cmath> | |||
#include <type_traits> | |||
#include <utility> | |||
namespace input { | |||
void control_map::connect(::event::queue& queue) | |||
{ | |||
subscriptions.emplace_back(queue.subscribe<event::gamepad_axis_moved>(std::bind_front(&control_map::handle_gamepad_axis_moved, this))); | |||
subscriptions.emplace_back(queue.subscribe<event::gamepad_button_pressed>(std::bind_front(&control_map::handle_gamepad_button_pressed, this))); | |||
subscriptions.emplace_back(queue.subscribe<event::gamepad_button_released>(std::bind_front(&control_map::handle_gamepad_button_released, this))); | |||
subscriptions.emplace_back(queue.subscribe<event::key_pressed>(std::bind_front(&control_map::handle_key_pressed, this))); | |||
subscriptions.emplace_back(queue.subscribe<event::key_released>(std::bind_front(&control_map::handle_key_released, this))); | |||
subscriptions.emplace_back(queue.subscribe<event::mouse_button_pressed>(std::bind_front(&control_map::handle_mouse_button_pressed, this))); | |||
subscriptions.emplace_back(queue.subscribe<event::mouse_button_released>(std::bind_front(&control_map::handle_mouse_button_released, this))); | |||
subscriptions.emplace_back(queue.subscribe<event::mouse_moved>(std::bind_front(&control_map::handle_mouse_moved, this))); | |||
subscriptions.emplace_back(queue.subscribe<event::mouse_scrolled>(std::bind_front(&control_map::handle_mouse_scrolled, this))); | |||
} | |||
void control_map::disconnect() | |||
{ | |||
subscriptions.clear(); | |||
} | |||
void control_map::add_mapping(control& control, const mapping& mapping) | |||
{ | |||
switch (mapping.get_mapping_type()) | |||
{ | |||
case mapping_type::gamepad_axis: | |||
add_mapping(control, static_cast<const gamepad_axis_mapping&>(mapping)); | |||
break; | |||
case mapping_type::gamepad_button: | |||
add_mapping(control, static_cast<const gamepad_button_mapping&>(mapping)); | |||
break; | |||
case mapping_type::key: | |||
add_mapping(control, static_cast<const key_mapping&>(mapping)); | |||
break; | |||
case mapping_type::mouse_button: | |||
add_mapping(control, static_cast<const mouse_button_mapping&>(mapping)); | |||
break; | |||
case mapping_type::mouse_motion: | |||
add_mapping(control, static_cast<const mouse_motion_mapping&>(mapping)); | |||
break; | |||
case mapping_type::mouse_scroll: | |||
add_mapping(control, static_cast<const mouse_scroll_mapping&>(mapping)); | |||
break; | |||
default: | |||
//std::unreachable(); | |||
break; | |||
} | |||
} | |||
void control_map::add_mapping(control& control, gamepad_axis_mapping&& mapping) | |||
{ | |||
gamepad_axis_mappings.emplace_back(&control, mapping); | |||
} | |||
void control_map::add_mapping(control& control, gamepad_button_mapping&& mapping) | |||
{ | |||
gamepad_button_mappings.emplace_back(&control, mapping); | |||
} | |||
void control_map::add_mapping(control& control, key_mapping&& mapping) | |||
{ | |||
key_mappings.emplace_back(&control, mapping); | |||
} | |||
void control_map::add_mapping(control& control, mouse_button_mapping&& mapping) | |||
{ | |||
mouse_button_mappings.emplace_back(&control, mapping); | |||
} | |||
void control_map::add_mapping(control& control, mouse_motion_mapping&& mapping) | |||
{ | |||
mouse_motion_mappings.emplace_back(&control, mapping); | |||
} | |||
void control_map::add_mapping(control& control, mouse_scroll_mapping&& mapping) | |||
{ | |||
mouse_scroll_mappings.emplace_back(&control, mapping); | |||
} | |||
void control_map::remove_mappings(control& control, mapping_type type) | |||
{ | |||
auto predicate = [&](const auto& tuple) -> bool | |||
{ | |||
return std::get<0>(tuple) == &control; | |||
}; | |||
switch (type) | |||
{ | |||
case mapping_type::gamepad_axis: | |||
std::erase_if(gamepad_axis_mappings, predicate); | |||
break; | |||
case mapping_type::gamepad_button: | |||
std::erase_if(gamepad_button_mappings, predicate); | |||
break; | |||
case mapping_type::key: | |||
std::erase_if(key_mappings, predicate); | |||
break; | |||
case mapping_type::mouse_button: | |||
std::erase_if(mouse_button_mappings, predicate); | |||
break; | |||
case mapping_type::mouse_motion: | |||
std::erase_if(mouse_motion_mappings, predicate); | |||
break; | |||
case mapping_type::mouse_scroll: | |||
std::erase_if(mouse_scroll_mappings, predicate); | |||
break; | |||
default: | |||
//std::unreachable(); | |||
break; | |||
} | |||
} | |||
void control_map::remove_mappings(control& control) | |||
{ | |||
auto predicate = [&](const auto& tuple) -> bool | |||
{ | |||
return std::get<0>(tuple) == &control; | |||
}; | |||
std::erase_if(gamepad_axis_mappings, predicate); | |||
std::erase_if(gamepad_button_mappings, predicate); | |||
std::erase_if(key_mappings, predicate); | |||
std::erase_if(mouse_button_mappings, predicate); | |||
std::erase_if(mouse_motion_mappings, predicate); | |||
std::erase_if(mouse_scroll_mappings, predicate); | |||
} | |||
void control_map::remove_mappings() | |||
{ | |||
gamepad_axis_mappings.clear(); | |||
gamepad_button_mappings.clear(); | |||
key_mappings.clear(); | |||
mouse_button_mappings.clear(); | |||
mouse_motion_mappings.clear(); | |||
mouse_scroll_mappings.clear(); | |||
} | |||
void control_map::handle_gamepad_axis_moved(const event::gamepad_axis_moved& event) | |||
{ | |||
for (const auto& [control, mapping]: gamepad_axis_mappings) | |||
{ | |||
if (mapping.axis == event.axis && | |||
(!mapping.gamepad || mapping.gamepad == event.gamepad)) | |||
{ | |||
if (std::signbit(event.position) == mapping.direction) | |||
{ | |||
control->evaluate(std::abs(event.position)); | |||
} | |||
else | |||
{ | |||
control->evaluate(0.0f); | |||
} | |||
} | |||
} | |||
} | |||
void control_map::handle_gamepad_button_pressed(const event::gamepad_button_pressed& event) | |||
{ | |||
for (const auto& [control, mapping]: gamepad_button_mappings) | |||
{ | |||
if (mapping.button == event.button && | |||
(!mapping.gamepad || mapping.gamepad == event.gamepad)) | |||
{ | |||
control->evaluate(1.0f); | |||
} | |||
} | |||
} | |||
void control_map::handle_gamepad_button_released(const event::gamepad_button_released& event) | |||
{ | |||
for (const auto& [control, mapping]: gamepad_button_mappings) | |||
{ | |||
if (mapping.button == event.button && | |||
(!mapping.gamepad || mapping.gamepad == event.gamepad)) | |||
{ | |||
control->evaluate(0.0f); | |||
} | |||
} | |||
} | |||
void control_map::handle_key_pressed(const event::key_pressed& event) | |||
{ | |||
for (const auto& [control, mapping]: key_mappings) | |||
{ | |||
if (mapping.scancode == event.scancode && | |||
(!mapping.keyboard || mapping.keyboard == event.keyboard)) | |||
{ | |||
control->evaluate(1.0f); | |||
} | |||
} | |||
} | |||
void control_map::handle_key_released(const event::key_released& event) | |||
{ | |||
for (const auto& [control, mapping]: key_mappings) | |||
{ | |||
if (mapping.scancode == event.scancode && | |||
(!mapping.keyboard || mapping.keyboard == event.keyboard)) | |||
{ | |||
control->evaluate(0.0f); | |||
} | |||
} | |||
} | |||
void control_map::handle_mouse_moved(const event::mouse_moved& event) | |||
{ | |||
for (const auto& [control, mapping]: mouse_motion_mappings) | |||
{ | |||
if (!mapping.mouse || mapping.mouse == event.mouse) | |||
{ | |||
const float difference = static_cast<float>(event.difference[static_cast<std::underlying_type_t<mouse_motion_axis>>(mapping.axis)]); | |||
if (difference && std::signbit(difference) == mapping.direction) | |||
{ | |||
control->evaluate(std::abs(difference)); | |||
control->evaluate(0.0f); | |||
} | |||
} | |||
} | |||
} | |||
void control_map::handle_mouse_scrolled(const event::mouse_scrolled& event) | |||
{ | |||
for (const auto& [control, mapping]: mouse_scroll_mappings) | |||
{ | |||
if (!mapping.mouse || mapping.mouse == event.mouse) | |||
{ | |||
const auto velocity = event.velocity[static_cast<std::underlying_type_t<mouse_scroll_axis>>(mapping.axis)]; | |||
if (velocity && std::signbit(velocity) == mapping.direction) | |||
{ | |||
control->evaluate(std::abs(velocity)); | |||
control->evaluate(0.0f); | |||
} | |||
} | |||
} | |||
} | |||
void control_map::handle_mouse_button_pressed(const event::mouse_button_pressed& event) | |||
{ | |||
for (const auto& [control, mapping]: mouse_button_mappings) | |||
{ | |||
if (mapping.button == event.button && | |||
(!mapping.mouse || mapping.mouse == event.mouse)) | |||
{ | |||
control->evaluate(1.0f); | |||
} | |||
} | |||
} | |||
void control_map::handle_mouse_button_released(const event::mouse_button_released& event) | |||
{ | |||
for (const auto& [control, mapping]: mouse_button_mappings) | |||
{ | |||
if (mapping.button == event.button && | |||
(!mapping.mouse || mapping.mouse == event.mouse)) | |||
{ | |||
control->evaluate(0.0f); | |||
} | |||
} | |||
} | |||
} // namespace input |
@ -0,0 +1,111 @@ | |||
/* | |||
* Copyright (C) 2023 Christopher J. Howard | |||
* | |||
* This file is part of Antkeeper source code. | |||
* | |||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation, either version 3 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* Antkeeper source code is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License | |||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | |||
#ifndef ANTKEEER_INPUT_CONTROL_MAP_HPP | |||
#define ANTKEEER_INPUT_CONTROL_MAP_HPP | |||
#include "event/subscription.hpp" | |||
#include "event/queue.hpp" | |||
#include "input/control.hpp" | |||
#include "input/event.hpp" | |||
#include "input/mapping.hpp" | |||
#include <memory> | |||
#include <tuple> | |||
#include <unordered_map> | |||
#include <vector> | |||
namespace input { | |||
/** | |||
* Maps input to a set of contextually-related controls. | |||
*/ | |||
class control_map | |||
{ | |||
public: | |||
/** | |||
* Connects the input event signals of an event queue to the control map. | |||
* | |||
* @param queue Event queue to connect. | |||
*/ | |||
void connect(::event::queue& queue); | |||
/** | |||
* Disconnects all input event signals from the control map. | |||
*/ | |||
void disconnect(); | |||
/** | |||
* Maps input to a control. | |||
* | |||
* @param control Control to which input will be mapped. | |||
* @param mapping Input mapping to add. | |||
*/ | |||
/// @{ | |||
void add_mapping(control& control, const mapping& mapping); | |||
void add_mapping(control& control, gamepad_axis_mapping&& mapping); | |||
void add_mapping(control& control, gamepad_button_mapping&& mapping); | |||
void add_mapping(control& control, key_mapping&& mapping); | |||
void add_mapping(control& control, mouse_button_mapping&& mapping); | |||
void add_mapping(control& control, mouse_motion_mapping&& mapping); | |||
void add_mapping(control& control, mouse_scroll_mapping&& mapping); | |||
/// @} | |||
/** | |||
* Unmaps input from a control. | |||
* | |||
* @param control Control from which input will be unmapped. | |||
* @param type Type of input mapping to remove. | |||
*/ | |||
void remove_mappings(control& control, mapping_type type); | |||
/** | |||
* Unmaps all input from a control. | |||
* | |||
* @param control Control from which input will be unmapped. | |||
*/ | |||
void remove_mappings(control& control); | |||
/** | |||
* Unmaps all input from all controls in the control map. | |||
*/ | |||
void remove_mappings(); | |||
private: | |||
void handle_gamepad_axis_moved(const event::gamepad_axis_moved& event); | |||
void handle_gamepad_button_pressed(const event::gamepad_button_pressed& event); | |||
void handle_gamepad_button_released(const event::gamepad_button_released& event); | |||
void handle_key_pressed(const event::key_pressed& event); | |||
void handle_key_released(const event::key_released& event); | |||
void handle_mouse_button_pressed(const event::mouse_button_pressed& event); | |||
void handle_mouse_button_released(const event::mouse_button_released& event); | |||
void handle_mouse_moved(const event::mouse_moved& event); | |||
void handle_mouse_scrolled(const event::mouse_scrolled& event); | |||
std::vector<std::shared_ptr<::event::subscription>> subscriptions; | |||
std::vector<std::tuple<control*, gamepad_axis_mapping>> gamepad_axis_mappings; | |||
std::vector<std::tuple<control*, gamepad_button_mapping>> gamepad_button_mappings; | |||
std::vector<std::tuple<control*, key_mapping>> key_mappings; | |||
std::vector<std::tuple<control*, mouse_button_mapping>> mouse_button_mappings; | |||
std::vector<std::tuple<control*, mouse_motion_mapping>> mouse_motion_mappings; | |||
std::vector<std::tuple<control*, mouse_scroll_mapping>> mouse_scroll_mappings; | |||
}; | |||
} // namespace input | |||
#endif // ANTKEEER_INPUT_CONTROL_MAP_HPP |
@ -1,83 +0,0 @@ | |||
/* | |||
* Copyright (C) 2023 Christopher J. Howard | |||
* | |||
* This file is part of Antkeeper source code. | |||
* | |||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation, either version 3 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* Antkeeper source code is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License | |||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | |||
#ifndef ANTKEEPER_INPUT_CONTROL_SET_HPP | |||
#define ANTKEEPER_INPUT_CONTROL_SET_HPP | |||
#include <list> | |||
namespace input { | |||
class control; | |||
/** | |||
* A set of controls which can be managed simultaneously. | |||
*/ | |||
class control_set | |||
{ | |||
public: | |||
/** | |||
* Adds a control to the control set. | |||
* | |||
* @param control Pointer to the control to add. | |||
*/ | |||
void add_control(control* control); | |||
/** | |||
* Removes a control from the control set. | |||
* | |||
* @param control Pointer to the control to remove. | |||
*/ | |||
void remove_control(control* control); | |||
/** | |||
* Removes all controls from the control set. | |||
*/ | |||
void remove_controls(); | |||
/** | |||
* Calls control::update() on each control in this control set. | |||
*/ | |||
void update(); | |||
/** | |||
* Enables or disables callbacks for all controls in the control set. | |||
* | |||
* @param enabled Whether to enable or disable callbacks for all controls in the control set. | |||
*/ | |||
void set_callbacks_enabled(bool enabled); | |||
/** | |||
* Returns the list of controls in the control set. | |||
*/ | |||
const std::list<control*>* get_controls() const; | |||
private: | |||
std::list<control*> controls; | |||
}; | |||
inline const std::list<control*>* control_set::get_controls() const | |||
{ | |||
return &controls; | |||
} | |||
} // namespace input | |||
#endif // ANTKEEPER_INPUT_CONTROL_SET_HPP | |||
@ -0,0 +1,121 @@ | |||
/* | |||
* Copyright (C) 2023 Christopher J. Howard | |||
* | |||
* This file is part of Antkeeper source code. | |||
* | |||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation, either version 3 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* Antkeeper source code is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License | |||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | |||
#include "input/device-manager.hpp" | |||
namespace input { | |||
void device_manager::register_device(device& device) | |||
{ | |||
subscriptions.emplace(&device, device.get_connected_channel().subscribe(event_queue)); | |||
subscriptions.emplace(&device, device.get_disconnected_channel().subscribe(event_queue)); | |||
switch (device.get_device_type()) | |||
{ | |||
case device_type::gamepad: | |||
register_gamepad(static_cast<gamepad&>(device)); | |||
break; | |||
case device_type::keyboard: | |||
register_keyboard(static_cast<keyboard&>(device)); | |||
break; | |||
case device_type::mouse: | |||
register_mouse(static_cast<mouse&>(device)); | |||
break; | |||
default: | |||
//std::unreachable(); | |||
break; | |||
} | |||
} | |||
void device_manager::unregister_device(device& device) | |||
{ | |||
subscriptions.erase(&device); | |||
switch (device.get_device_type()) | |||
{ | |||
case device_type::gamepad: | |||
unregister_gamepad(static_cast<gamepad&>(device)); | |||
break; | |||
case device_type::keyboard: | |||
unregister_keyboard(static_cast<keyboard&>(device)); | |||
break; | |||
case device_type::mouse: | |||
unregister_mouse(static_cast<mouse&>(device)); | |||
break; | |||
default: | |||
//std::unreachable(); | |||
break; | |||
} | |||
} | |||
void device_manager::register_gamepad(gamepad& gamepad) | |||
{ | |||
// Connect gamepad event signals to the event queue | |||
subscriptions.emplace(&gamepad, gamepad.get_axis_moved_channel().subscribe(event_queue)); | |||
subscriptions.emplace(&gamepad, gamepad.get_button_pressed_channel().subscribe(event_queue)); | |||
subscriptions.emplace(&gamepad, gamepad.get_button_released_channel().subscribe(event_queue)); | |||
// Add gamepad to list of gamepads | |||
gamepads.emplace(&gamepad); | |||
} | |||
void device_manager::register_keyboard(keyboard& keyboard) | |||
{ | |||
// Connect keyboard event signals to the event queue | |||
subscriptions.emplace(&keyboard, keyboard.get_key_pressed_channel().subscribe(event_queue)); | |||
subscriptions.emplace(&keyboard, keyboard.get_key_released_channel().subscribe(event_queue)); | |||
// Add keyboard to list of keyboards | |||
keyboards.emplace(&keyboard); | |||
} | |||
void device_manager::register_mouse(mouse& mouse) | |||
{ | |||
// Connect mouse event signals to the event queue | |||
subscriptions.emplace(&mouse, mouse.get_button_pressed_channel().subscribe(event_queue)); | |||
subscriptions.emplace(&mouse, mouse.get_button_released_channel().subscribe(event_queue)); | |||
subscriptions.emplace(&mouse, mouse.get_moved_channel().subscribe(event_queue)); | |||
subscriptions.emplace(&mouse, mouse.get_scrolled_channel().subscribe(event_queue)); | |||
// Add mouse to list of mice | |||
mice.emplace(&mouse); | |||
} | |||
void device_manager::unregister_gamepad(gamepad& gamepad) | |||
{ | |||
gamepads.erase(&gamepad); | |||
} | |||
void device_manager::unregister_keyboard(keyboard& keyboard) | |||
{ | |||
keyboards.erase(&keyboard); | |||
} | |||
void device_manager::unregister_mouse(mouse& mouse) | |||
{ | |||
mice.erase(&mouse); | |||
} | |||
} // namespace input |
@ -0,0 +1,97 @@ | |||
/* | |||
* Copyright (C) 2023 Christopher J. Howard | |||
* | |||
* This file is part of Antkeeper source code. | |||
* | |||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation, either version 3 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* Antkeeper source code is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License | |||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | |||
#ifndef ANTKEEPER_INPUT_DEVICE_MANAGER_HPP | |||
#define ANTKEEPER_INPUT_DEVICE_MANAGER_HPP | |||
#include "input/device.hpp" | |||
#include "input/gamepad.hpp" | |||
#include "input/keyboard.hpp" | |||
#include "input/mouse.hpp" | |||
#include "event/queue.hpp" | |||
#include <map> | |||
#include <memory> | |||
#include <unordered_set> | |||
namespace input { | |||
/** | |||
* Manages virtual input devices. | |||
*/ | |||
class device_manager | |||
{ | |||
public: | |||
/** | |||
* Registers an input device. | |||
* | |||
* @param device Input device to register. | |||
*/ | |||
void register_device(device& device); | |||
/** | |||
* Unregisters an input device. | |||
* | |||
* @param device Input device to unregister. | |||
*/ | |||
void unregister_device(device& device); | |||
/** | |||
* Returns the event queue associated with registered input devices. | |||
*/ | |||
[[nodiscard]] inline ::event::queue& get_event_queue() noexcept | |||
{ | |||
return event_queue; | |||
} | |||
/// Returns the set of registered gamepads. | |||
[[nodiscard]] inline const std::unordered_set<gamepad*>& get_gamepads() noexcept | |||
{ | |||
return gamepads; | |||
} | |||
/// Returns the set of registered keyboards. | |||
[[nodiscard]] inline const std::unordered_set<keyboard*>& get_keyboards() noexcept | |||
{ | |||
return keyboards; | |||
} | |||
/// Returns the set of registered mice. | |||
[[nodiscard]] inline const std::unordered_set<mouse*>& get_mice() noexcept | |||
{ | |||
return mice; | |||
} | |||
private: | |||
void register_gamepad(gamepad& gamepad); | |||
void register_keyboard(keyboard& keyboard); | |||
void register_mouse(mouse& mouse); | |||
void unregister_gamepad(gamepad& gamepad); | |||
void unregister_keyboard(keyboard& keyboard); | |||
void unregister_mouse(mouse& mouse); | |||
::event::queue event_queue; | |||
std::multimap<device*, std::shared_ptr<::event::subscription>> subscriptions; | |||
std::unordered_set<gamepad*> gamepads; | |||
std::unordered_set<keyboard*> keyboards; | |||
std::unordered_set<mouse*> mice; | |||
}; | |||
} // namespace input | |||
#endif // ANTKEEPER_INPUT_DEVICE_MANAGER_HPP |
@ -0,0 +1,40 @@ | |||
/* | |||
* Copyright (C) 2023 Christopher J. Howard | |||
* | |||
* This file is part of Antkeeper source code. | |||
* | |||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation, either version 3 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* Antkeeper source code is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License | |||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | |||
#ifndef ANTKEEPER_INPUT_DEVICE_TYPE_HPP | |||
#define ANTKEEPER_INPUT_DEVICE_TYPE_HPP | |||
namespace input { | |||
/// Input device types. | |||
enum class device_type | |||
{ | |||
/// Gamepad input device. | |||
gamepad, | |||
/// Keyboard input device. | |||
keyboard, | |||
/// Mouse input device. | |||
mouse | |||
}; | |||
} // namespace input | |||
#endif // ANTKEEPER_INPUT_DEVICE_TYPE_HPP |
@ -1,399 +0,0 @@ | |||
/* | |||
* Copyright (C) 2023 Christopher J. Howard | |||
* | |||
* This file is part of Antkeeper source code. | |||
* | |||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation, either version 3 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* Antkeeper source code is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License | |||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | |||
#include "event-router.hpp" | |||
#include "control.hpp" | |||
#include "mapping.hpp" | |||
#include "mouse.hpp" | |||
#include "event/event-dispatcher.hpp" | |||
namespace input { | |||
event_router::event_router(): | |||
event_dispatcher(nullptr) | |||
{} | |||
event_router::~event_router() | |||
{ | |||
remove_mappings(); | |||
set_event_dispatcher(nullptr); | |||
} | |||
void event_router::add_mapping(const mapping& mapping) | |||
{ | |||
control* control = mapping.control; | |||
switch (mapping.get_type()) | |||
{ | |||
case mapping_type::key: | |||
{ | |||
input::key_mapping* key_mapping = new input::key_mapping(static_cast<const input::key_mapping&>(mapping)); | |||
key_mappings.push_back(key_mapping); | |||
controls[control].push_back(key_mapping); | |||
break; | |||
} | |||
case mapping_type::mouse_motion: | |||
{ | |||
input::mouse_motion_mapping* mouse_motion_mapping = new input::mouse_motion_mapping(static_cast<const input::mouse_motion_mapping&>(mapping)); | |||
mouse_motion_mappings.push_back(mouse_motion_mapping); | |||
controls[control].push_back(mouse_motion_mapping); | |||
break; | |||
} | |||
case mapping_type::mouse_wheel: | |||
{ | |||
input::mouse_wheel_mapping* mouse_wheel_mapping = new input::mouse_wheel_mapping(static_cast<const input::mouse_wheel_mapping&>(mapping)); | |||
mouse_wheel_mappings.push_back(mouse_wheel_mapping); | |||
controls[control].push_back(mouse_wheel_mapping); | |||
break; | |||
} | |||
case mapping_type::mouse_button: | |||
{ | |||
input::mouse_button_mapping* mouse_button_mapping = new input::mouse_button_mapping(static_cast<const input::mouse_button_mapping&>(mapping)); | |||
mouse_button_mappings.push_back(mouse_button_mapping); | |||
controls[control].push_back(mouse_button_mapping); | |||
break; | |||
} | |||
case mapping_type::gamepad_axis: | |||
{ | |||
input::gamepad_axis_mapping* gamepad_axis_mapping = new input::gamepad_axis_mapping(static_cast<const input::gamepad_axis_mapping&>(mapping)); | |||
gamepad_axis_mappings.push_back(gamepad_axis_mapping); | |||
controls[control].push_back(gamepad_axis_mapping); | |||
break; | |||
} | |||
case mapping_type::gamepad_button: | |||
{ | |||
input::gamepad_button_mapping* gamepad_button_mapping = new input::gamepad_button_mapping(static_cast<const input::gamepad_button_mapping&>(mapping)); | |||
gamepad_button_mappings.push_back(gamepad_button_mapping); | |||
controls[control].push_back(gamepad_button_mapping); | |||
break; | |||
} | |||
default: | |||
break; | |||
} | |||
} | |||
void event_router::remove_mappings(control* control) | |||
{ | |||
auto it = controls.find(control); | |||
if (it != controls.end()) | |||
{ | |||
for (mapping* mapping: it->second) | |||
{ | |||
switch (mapping->get_type()) | |||
{ | |||
case mapping_type::key: | |||
key_mappings.remove(static_cast<key_mapping*>(mapping)); | |||
break; | |||
case mapping_type::mouse_motion: | |||
mouse_motion_mappings.remove(static_cast<mouse_motion_mapping*>(mapping)); | |||
break; | |||
case mapping_type::mouse_wheel: | |||
mouse_wheel_mappings.remove(static_cast<mouse_wheel_mapping*>(mapping)); | |||
break; | |||
case mapping_type::mouse_button: | |||
mouse_button_mappings.remove(static_cast<mouse_button_mapping*>(mapping)); | |||
break; | |||
case mapping_type::gamepad_axis: | |||
gamepad_axis_mappings.remove(static_cast<gamepad_axis_mapping*>(mapping)); | |||
break; | |||
case mapping_type::gamepad_button: | |||
gamepad_button_mappings.remove(static_cast<gamepad_button_mapping*>(mapping)); | |||
break; | |||
default: | |||
break; | |||
} | |||
delete mapping; | |||
} | |||
controls.erase(it); | |||
} | |||
} | |||
void event_router::remove_mappings(control* control, mapping_type type) | |||
{ | |||
auto it = controls.find(control); | |||
if (it != controls.end()) | |||
{ | |||
std::list<mapping*> flagged_mappings; | |||
for (mapping* mapping: it->second) | |||
{ | |||
if (mapping->get_type() != type) | |||
continue; | |||
// Flag mapping for deletion | |||
flagged_mappings.push_back(mapping); | |||
switch (mapping->get_type()) | |||
{ | |||
case mapping_type::key: | |||
key_mappings.remove(static_cast<key_mapping*>(mapping)); | |||
break; | |||
case mapping_type::mouse_motion: | |||
mouse_motion_mappings.remove(static_cast<mouse_motion_mapping*>(mapping)); | |||
break; | |||
case mapping_type::mouse_wheel: | |||
mouse_wheel_mappings.remove(static_cast<mouse_wheel_mapping*>(mapping)); | |||
break; | |||
case mapping_type::mouse_button: | |||
mouse_button_mappings.remove(static_cast<mouse_button_mapping*>(mapping)); | |||
break; | |||
case mapping_type::gamepad_axis: | |||
gamepad_axis_mappings.remove(static_cast<gamepad_axis_mapping*>(mapping)); | |||
break; | |||
case mapping_type::gamepad_button: | |||
gamepad_button_mappings.remove(static_cast<gamepad_button_mapping*>(mapping)); | |||
break; | |||
default: | |||
break; | |||
} | |||
} | |||
// Delete flagged mappings | |||
for (mapping* mapping: flagged_mappings) | |||
{ | |||
it->second.remove(mapping); | |||
delete mapping; | |||
} | |||
} | |||
} | |||
void event_router::set_event_dispatcher(::event_dispatcher* event_dispatcher) | |||
{ | |||
if (this->event_dispatcher) | |||
{ | |||
this->event_dispatcher->unsubscribe<key_pressed_event>(this); | |||
this->event_dispatcher->unsubscribe<key_released_event>(this); | |||
this->event_dispatcher->unsubscribe<mouse_moved_event>(this); | |||
this->event_dispatcher->unsubscribe<mouse_wheel_scrolled_event>(this); | |||
this->event_dispatcher->unsubscribe<mouse_button_pressed_event>(this); | |||
this->event_dispatcher->unsubscribe<mouse_button_released_event>(this); | |||
this->event_dispatcher->unsubscribe<gamepad_axis_moved_event>(this); | |||
this->event_dispatcher->unsubscribe<gamepad_button_pressed_event>(this); | |||
this->event_dispatcher->unsubscribe<gamepad_button_released_event>(this); | |||
} | |||
this->event_dispatcher = event_dispatcher; | |||
if (event_dispatcher) | |||
{ | |||
event_dispatcher->subscribe<key_pressed_event>(this); | |||
event_dispatcher->subscribe<key_released_event>(this); | |||
event_dispatcher->subscribe<mouse_moved_event>(this); | |||
event_dispatcher->subscribe<mouse_wheel_scrolled_event>(this); | |||
event_dispatcher->subscribe<mouse_button_pressed_event>(this); | |||
event_dispatcher->subscribe<mouse_button_released_event>(this); | |||
event_dispatcher->subscribe<gamepad_axis_moved_event>(this); | |||
event_dispatcher->subscribe<gamepad_button_pressed_event>(this); | |||
event_dispatcher->subscribe<gamepad_button_released_event>(this); | |||
} | |||
} | |||
void event_router::remove_mappings() | |||
{ | |||
for (auto it = controls.begin(); it != controls.end(); ++it) | |||
{ | |||
for (mapping* mapping: it->second) | |||
{ | |||
delete mapping; | |||
} | |||
} | |||
controls.clear(); | |||
key_mappings.clear(); | |||
mouse_motion_mappings.clear(); | |||
mouse_wheel_mappings.clear(); | |||
mouse_button_mappings.clear(); | |||
gamepad_axis_mappings.clear(); | |||
gamepad_button_mappings.clear(); | |||
} | |||
const std::list<mapping*>* event_router::get_mappings(control* control) const | |||
{ | |||
auto it = controls.find(control); | |||
if (it == controls.end()) | |||
{ | |||
return nullptr; | |||
} | |||
return &it->second; | |||
} | |||
void event_router::handle_event(const key_pressed_event& event) | |||
{ | |||
for (const key_mapping* mapping: key_mappings) | |||
{ | |||
if ((!mapping->keyboard || mapping->keyboard == event.keyboard) && mapping->scancode == event.scancode) | |||
{ | |||
mapping->control->set_current_value(1.0f); | |||
} | |||
} | |||
} | |||
void event_router::handle_event(const key_released_event& event) | |||
{ | |||
for (const key_mapping* mapping: key_mappings) | |||
{ | |||
if ((!mapping->keyboard || mapping->keyboard == event.keyboard) && mapping->scancode == event.scancode) | |||
{ | |||
mapping->control->set_current_value(0.0f); | |||
} | |||
} | |||
} | |||
void event_router::handle_event(const mouse_moved_event& event) | |||
{ | |||
for (const mouse_motion_mapping* mapping: mouse_motion_mappings) | |||
{ | |||
if (!mapping->mouse || mapping->mouse == event.mouse) | |||
{ | |||
if (mapping->axis == mouse_motion_axis::negative_x && event.dx < 0) | |||
{ | |||
mapping->control->set_temporary_value(mapping->control->get_current_value() - event.dx); | |||
} | |||
else if (mapping->axis == mouse_motion_axis::positive_x && event.dx > 0) | |||
{ | |||
mapping->control->set_temporary_value(mapping->control->get_current_value() + event.dx); | |||
} | |||
else if (mapping->axis == mouse_motion_axis::negative_y && event.dy < 0) | |||
{ | |||
mapping->control->set_temporary_value(mapping->control->get_current_value() - event.dy); | |||
} | |||
else if (mapping->axis == mouse_motion_axis::positive_y && event.dy > 0) | |||
{ | |||
mapping->control->set_temporary_value(mapping->control->get_current_value() + event.dy); | |||
} | |||
} | |||
} | |||
} | |||
void event_router::handle_event(const mouse_wheel_scrolled_event& event) | |||
{ | |||
for (const mouse_wheel_mapping* mapping: mouse_wheel_mappings) | |||
{ | |||
if (!mapping->mouse || mapping->mouse == event.mouse) | |||
{ | |||
if (mapping->axis == mouse_wheel_axis::negative_x && event.x < 0) | |||
{ | |||
mapping->control->set_temporary_value(mapping->control->get_current_value() - event.x); | |||
} | |||
else if (mapping->axis == mouse_wheel_axis::positive_x && event.x > 0) | |||
{ | |||
mapping->control->set_temporary_value(mapping->control->get_current_value() + event.x); | |||
} | |||
else if (mapping->axis == mouse_wheel_axis::negative_y && event.y < 0) | |||
{ | |||
mapping->control->set_temporary_value(mapping->control->get_current_value() - event.y); | |||
} | |||
else if (mapping->axis == mouse_wheel_axis::positive_y && event.y > 0) | |||
{ | |||
mapping->control->set_temporary_value(mapping->control->get_current_value() + event.y); | |||
} | |||
} | |||
} | |||
} | |||
void event_router::handle_event(const mouse_button_pressed_event& event) | |||
{ | |||
for (const mouse_button_mapping* mapping: mouse_button_mappings) | |||
{ | |||
if ((!mapping->mouse || mapping->mouse == event.mouse) && mapping->button == event.button) | |||
{ | |||
mapping->control->set_current_value(1.0f); | |||
} | |||
} | |||
} | |||
void event_router::handle_event(const mouse_button_released_event& event) | |||
{ | |||
for (const mouse_button_mapping* mapping: mouse_button_mappings) | |||
{ | |||
if ((!mapping->mouse || mapping->mouse == event.mouse) && mapping->button == event.button) | |||
{ | |||
mapping->control->set_current_value(0.0f); | |||
} | |||
} | |||
} | |||
void event_router::handle_event(const gamepad_axis_moved_event& event) | |||
{ | |||
for (const gamepad_axis_mapping* mapping: gamepad_axis_mappings) | |||
{ | |||
if ((!mapping->controller || mapping->controller == event.controller) && mapping->axis == event.axis) | |||
{ | |||
if (mapping->negative && event.value >= 0.0f || !mapping->negative && event.value <= 0.0f) | |||
{ | |||
mapping->control->set_current_value(0.0f); | |||
} | |||
else | |||
{ | |||
mapping->control->set_current_value(std::abs(event.value)); | |||
} | |||
} | |||
} | |||
} | |||
void event_router::handle_event(const gamepad_button_pressed_event& event) | |||
{ | |||
for (const gamepad_button_mapping* mapping: gamepad_button_mappings) | |||
{ | |||
if ((!mapping->controller || mapping->controller == event.controller) && mapping->button == event.button) | |||
{ | |||
mapping->control->set_current_value(1.0f); | |||
} | |||
} | |||
} | |||
void event_router::handle_event(const gamepad_button_released_event& event) | |||
{ | |||
for (const gamepad_button_mapping* mapping: gamepad_button_mappings) | |||
{ | |||
if ((!mapping->controller || mapping->controller == event.controller) && mapping->button == event.button) | |||
{ | |||
mapping->control->set_current_value(0.0f); | |||
} | |||
} | |||
} | |||
} // namespace input |
@ -1,127 +0,0 @@ | |||
/* | |||
* Copyright (C) 2023 Christopher J. Howard | |||
* | |||
* This file is part of Antkeeper source code. | |||
* | |||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation, either version 3 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* Antkeeper source code is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License | |||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | |||
#ifndef ANTKEEER_INPUT_EVENT_ROUTER_HPP | |||
#define ANTKEEER_INPUT_EVENT_ROUTER_HPP | |||
#include "event/input-events.hpp" | |||
#include "event/event-handler.hpp" | |||
#include "event/event-dispatcher.hpp" | |||
#include <list> | |||
#include <map> | |||
namespace input { | |||
class control; | |||
enum class mapping_type; | |||
class mapping; | |||
class key_mapping; | |||
class mouse_motion_mapping; | |||
class mouse_wheel_mapping; | |||
class mouse_button_mapping; | |||
class gamepad_axis_mapping; | |||
class gamepad_button_mapping; | |||
enum class mouse_motion_axis; | |||
enum class mouse_wheel_axis; | |||
/** | |||
* Uses input mappings to route input events to controls. | |||
*/ | |||
class event_router: | |||
public event_handler<key_pressed_event>, | |||
public event_handler<key_released_event>, | |||
public event_handler<mouse_moved_event>, | |||
public event_handler<mouse_wheel_scrolled_event>, | |||
public event_handler<mouse_button_pressed_event>, | |||
public event_handler<mouse_button_released_event>, | |||
public event_handler<gamepad_axis_moved_event>, | |||
public event_handler<gamepad_button_pressed_event>, | |||
public event_handler<gamepad_button_released_event> | |||
{ | |||
public: | |||
/** | |||
* Creates an input router and subscribes it to the input events of the specified event dispatcher. | |||
*/ | |||
event_router(); | |||
/** | |||
* Destroys an input router and unsubscribes it from input events. | |||
*/ | |||
~event_router(); | |||
/** | |||
* Adds an input mapping to the router. | |||
* | |||
* @param mapping Input mapping to add. | |||
*/ | |||
void add_mapping(const mapping& mapping); | |||
/** | |||
* Removes all input mappings from the router that are associated with the specified control. | |||
* | |||
* @param control Control with which associated input mappings should be removed. | |||
*/ | |||
void remove_mappings(control* control); | |||
/** | |||
* Removes all input mappings of a given type from the router that are associated with the specified control. | |||
* | |||
* @param control Control with which associated input mappings should be removed. | |||
* @param type Type of input mapping to be removed. | |||
*/ | |||
void remove_mappings(control* control, mapping_type type); | |||
/** | |||
* Removes all input mappings from the router. | |||
*/ | |||
void remove_mappings(); | |||
/** | |||
* Sets the event dispatcher to which this input event router will subscribe itself. | |||
*/ | |||
void set_event_dispatcher(event_dispatcher* event_dispatcher); | |||
/// Returns a list of mappings for the specified control, or nullptr if the control is unmapped. | |||
const std::list<mapping*>* get_mappings(control* control) const; | |||
private: | |||
virtual void handle_event(const key_pressed_event& event); | |||
virtual void handle_event(const key_released_event& event); | |||
virtual void handle_event(const mouse_moved_event& event); | |||
virtual void handle_event(const mouse_wheel_scrolled_event& event); | |||
virtual void handle_event(const mouse_button_pressed_event& event); | |||
virtual void handle_event(const mouse_button_released_event& event); | |||
virtual void handle_event(const gamepad_axis_moved_event& event); | |||
virtual void handle_event(const gamepad_button_pressed_event& event); | |||
virtual void handle_event(const gamepad_button_released_event& event); | |||
event_dispatcher* event_dispatcher; | |||
std::map<control*, std::list<mapping*>> controls; | |||
std::list<key_mapping*> key_mappings; | |||
std::list<mouse_motion_mapping*> mouse_motion_mappings; | |||
std::list<mouse_wheel_mapping*> mouse_wheel_mappings; | |||
std::list<mouse_button_mapping*> mouse_button_mappings; | |||
std::list<gamepad_axis_mapping*> gamepad_axis_mappings; | |||
std::list<gamepad_button_mapping*> gamepad_button_mappings; | |||
}; | |||
} // namespace input | |||
#endif // ANTKEEER_INPUT_EVENT_ROUTER_HPP | |||
@ -0,0 +1,283 @@ | |||
/* | |||
* Copyright (C) 2023 Christopher J. Howard | |||
* | |||
* This file is part of Antkeeper source code. | |||
* | |||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation, either version 3 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* Antkeeper source code is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License | |||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | |||
#ifndef ANTKEEPER_INPUT_EVENT_HPP | |||
#define ANTKEEPER_INPUT_EVENT_HPP | |||
#include "input/gamepad-axis.hpp" | |||
#include "input/gamepad-button.hpp" | |||
#include "input/mouse-motion-axis.hpp" | |||
#include "input/mouse-scroll-axis.hpp" | |||
#include "input/scancode.hpp" | |||
#include "input/mapping.hpp" | |||
#include "input/modifier-key.hpp" | |||
#include "math/vector.hpp" | |||
#include <cstdint> | |||
#include <memory> | |||
namespace input { | |||
class control; | |||
class device; | |||
class gamepad; | |||
class keyboard; | |||
class mouse; | |||
/** | |||
* Input events. | |||
*/ | |||
namespace event { | |||
/** | |||
* Event generated when a control has been activated. | |||
*/ | |||
struct control_activated | |||
{ | |||
/// Control that was activated. | |||
control* control; | |||
}; | |||
/** | |||
* Event generated while a control is active. | |||
*/ | |||
struct control_active | |||
{ | |||
/// Active control. | |||
control* control; | |||
/// Control input value. | |||
float input_value; | |||
}; | |||
/** | |||
* Event generated when a control has been deactivated. | |||
*/ | |||
struct control_deactivated | |||
{ | |||
/// Control that was deactivated. | |||
control* control; | |||
}; | |||
/** | |||
* Event generated when an input mapping has been generated. | |||
*/ | |||
struct input_mapped | |||
{ | |||
/// Input mapping that was generated. | |||
std::shared_ptr<mapping> mapping; | |||
}; | |||
/** | |||
* Event generated when an input device has been connected. | |||
*/ | |||
struct device_connected | |||
{ | |||
/// Device that was connected. | |||
device* device; | |||
}; | |||
/** | |||
* Event generated when an input device has been disconnected. | |||
*/ | |||
struct device_disconnected | |||
{ | |||
/// Device that was disconnected. | |||
device* device; | |||
}; | |||
/** | |||
* Event generated when a gamepad button has been pressed. | |||
*/ | |||
struct gamepad_button_pressed | |||
{ | |||
/// Gamepad that generated the event. | |||
gamepad* gamepad; | |||
/// Gamepad button being pressed. | |||
gamepad_button button; | |||
}; | |||
/** | |||
* Event generated when a gamepad button has been released. | |||
*/ | |||
struct gamepad_button_released | |||
{ | |||
/// Gamepad that generated the event. | |||
gamepad* gamepad; | |||
/// Gamepad button being released. | |||
gamepad_button button; | |||
}; | |||
/** | |||
* Event generated when a gamepad axis has been moved. | |||
*/ | |||
struct gamepad_axis_moved | |||
{ | |||
/// Gamepad that generated the event. | |||
gamepad* gamepad; | |||
/// Gamepad axis being moved. | |||
gamepad_axis axis; | |||
/// Position of the gamepad axis, on `[-1, 1]`. | |||
float position; | |||
}; | |||
/** | |||
* Event generated when a keyboard key has been pressed. | |||
*/ | |||
struct key_pressed | |||
{ | |||
/// Keyboard that generated the event. | |||
keyboard* keyboard; | |||
/// Scancode of the key being pressed. | |||
scancode scancode; | |||
/// `true` if the key press was generated by a key repeat, `false` otherwise. | |||
bool repeat; | |||
/// Bit mask containing the active modifier keys. | |||
std::uint16_t modifiers; | |||
}; | |||
/** | |||
* Event generated when a keyboard key has been released. | |||
*/ | |||
struct key_released | |||
{ | |||
/// Keyboard that generated the event. | |||
keyboard* keyboard; | |||
/// Scancode of the key being released. | |||
scancode scancode; | |||
/// `true` if the key release was generated by a key repeat, `false` otherwise. | |||
bool repeat; | |||
/// Bit mask containing the active modifier keys. | |||
std::uint16_t modifiers; | |||
}; | |||
/** | |||
* Event generated when a mouse has been moved. | |||
*/ | |||
struct mouse_moved | |||
{ | |||
/// Mouse that generated the event. | |||
mouse* mouse; | |||
/// Mouse position, in pixels, relative to the window. | |||
math::vector<std::int32_t, 2> position; | |||
/// Relative movement of the mouse, in pixels. | |||
math::vector<std::int32_t, 2> difference; | |||
}; | |||
/** | |||
* Event generated when a mouse button has been pressed. | |||
*/ | |||
struct mouse_button_pressed | |||
{ | |||
/// Mouse that generated the event. | |||
mouse* mouse; | |||
/// Mouse position, in pixels, relative to the window, when the button was pressed. | |||
math::vector<std::int32_t, 2> position; | |||
/// Mouse button being pressed. | |||
mouse_button button; | |||
}; | |||
/** | |||
* Event generated when a mouse button has been released. | |||
*/ | |||
struct mouse_button_released | |||
{ | |||
/// Mouse that generated the event. | |||
mouse* mouse; | |||
/// Mouse position, in pixels, relative to the window, when the button was released. | |||
math::vector<std::int32_t, 2> position; | |||
/// Mouse button being released. | |||
mouse_button button; | |||
}; | |||
/** | |||
* Event generated when a mouse has been scrolled. | |||
*/ | |||
struct mouse_scrolled | |||
{ | |||
/// Mouse that generated the event. | |||
mouse* mouse; | |||
/// Mouse position, in pixels, relative to the window, when the mouse was scrolled. | |||
math::vector<std::int32_t, 2> position; | |||
/// Scroll velocity. | |||
math::vector<float, 2> velocity; | |||
}; | |||
/** | |||
* Event generated when a window has been closed. | |||
*/ | |||
struct window_closed {}; | |||
/** | |||
* Event generated when a window has gained or lost focus. | |||
*/ | |||
struct window_focus_changed | |||
{ | |||
/// `true` if the window is in focus, `false` otherwise. | |||
bool in_focus; | |||
}; | |||
/** | |||
* Event generated when a window has been moved. | |||
*/ | |||
struct window_moved | |||
{ | |||
/// Position of the window, in pixels. | |||
math::vector<std::int32_t, 2> position; | |||
}; | |||
/** | |||
* Event generated when a window has been resized. | |||
*/ | |||
struct window_resized | |||
{ | |||
/// Window width, in pixels. | |||
std::int32_t window_width; | |||
/// Window height, in pixels. | |||
std::int32_t window_height; | |||
/// Viewport width, in pixels. | |||
std::int32_t viewport_width; | |||
/// Viewport height, in pixels. | |||
std::int32_t viewport_height; | |||
}; | |||
} // namespace event | |||
} // namespace input | |||
#endif // ANTKEEPER_INPUT_EVENT_HPP |
@ -0,0 +1,51 @@ | |||
/* | |||
* Copyright (C) 2023 Christopher J. Howard | |||
* | |||
* This file is part of Antkeeper source code. | |||
* | |||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation, either version 3 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* Antkeeper source code is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License | |||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | |||
#ifndef ANTKEEPER_INPUT_GAMEPAD_AXIS_HPP | |||
#define ANTKEEPER_INPUT_GAMEPAD_AXIS_HPP | |||
#include <cstdint> | |||
namespace input { | |||
/// Gamepad axes. | |||
enum class gamepad_axis: std::uint8_t | |||
{ | |||
/// Left stick X-axis. | |||
left_stick_x, | |||
/// Left stick Y-axis. | |||
left_stick_y, | |||
/// Right stick X-axis. | |||
right_stick_x, | |||
/// Right stick Y-axis. | |||
right_stick_y, | |||
/// Left trigger. | |||
left_trigger, | |||
/// Right trigger. | |||
right_trigger | |||
}; | |||
} // namespace input | |||
#endif // ANTKEEPER_INPUT_GAMEPAD_AXIS_HPP |
@ -0,0 +1,78 @@ | |||
/* | |||
* Copyright (C) 2023 Christopher J. Howard | |||
* | |||
* This file is part of Antkeeper source code. | |||
* | |||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation, either version 3 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* Antkeeper source code is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License | |||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | |||
#ifndef ANTKEEPER_INPUT_GAMEPAD_BUTTON_HPP | |||
#define ANTKEEPER_INPUT_GAMEPAD_BUTTON_HPP | |||
#include <cstdint> | |||
namespace input { | |||
/// Gamepad buttons. | |||
enum class gamepad_button: std::uint8_t | |||
{ | |||
/// A button. | |||
a, | |||
/// B button. | |||
b, | |||
/// X button. | |||
x, | |||
/// Y button. | |||
y, | |||
/// Back button. | |||
back, | |||
/// Guide button. | |||
guide, | |||
/// Start button. | |||
start, | |||
/// Left stick button. | |||
left_stick, | |||
/// Right stick button. | |||
right_stick, | |||
/// Left shoulder button. | |||
left_shoulder, | |||
/// Right shoulder button. | |||
right_shoulder, | |||
/// D-pad up button. | |||
dpad_up, | |||
/// D-pad down button. | |||
dpad_down, | |||
/// D-pad left button. | |||
dpad_left, | |||
/// D-pad right button. | |||
dpad_right | |||
}; | |||
} // namespace input | |||
#endif // ANTKEEPER_INPUT_GAMEPAD_BUTTON_HPP |
@ -1,38 +0,0 @@ | |||
/* | |||
* Copyright (C) 2023 Christopher J. Howard | |||
* | |||
* This file is part of Antkeeper source code. | |||
* | |||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation, either version 3 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* Antkeeper source code is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License | |||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | |||
#ifndef ANTKEEPER_INPUT_HPP | |||
#define ANTKEEPER_INPUT_HPP | |||
/// Input devices and events. | |||
namespace input {} | |||
#include "control.hpp" | |||
#include "control-set.hpp" | |||
#include "device.hpp" | |||
#include "event-router.hpp" | |||
#include "gamepad.hpp" | |||
#include "keyboard.hpp" | |||
#include "listener.hpp" | |||
#include "mapper.hpp" | |||
#include "mapping.hpp" | |||
#include "mouse.hpp" | |||
#include "scancode.hpp" | |||
#endif // ANTKEEPER_INPUT_HPP |
@ -1,111 +0,0 @@ | |||
/* | |||
* Copyright (C) 2023 Christopher J. Howard | |||
* | |||
* This file is part of Antkeeper source code. | |||
* | |||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation, either version 3 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* Antkeeper source code is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License | |||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | |||
#include "listener.hpp" | |||
#include "event/event-dispatcher.hpp" | |||
#include <iostream> | |||
namespace input { | |||
listener::listener(): | |||
event_dispatcher(nullptr), | |||
callback(nullptr), | |||
enabled(false) | |||
{} | |||
listener::~listener() | |||
{ | |||
set_event_dispatcher(nullptr); | |||
} | |||
void listener::set_event_dispatcher(::event_dispatcher* event_dispatcher) | |||
{ | |||
if (event_dispatcher != this->event_dispatcher) | |||
{ | |||
if (this->event_dispatcher) | |||
{ | |||
this->event_dispatcher->unsubscribe<key_pressed_event>(this); | |||
this->event_dispatcher->unsubscribe<mouse_moved_event>(this); | |||
this->event_dispatcher->unsubscribe<mouse_wheel_scrolled_event>(this); | |||
this->event_dispatcher->unsubscribe<mouse_button_pressed_event>(this); | |||
this->event_dispatcher->unsubscribe<gamepad_axis_moved_event>(this); | |||
this->event_dispatcher->unsubscribe<gamepad_button_pressed_event>(this); | |||
} | |||
if (event_dispatcher) | |||
{ | |||
event_dispatcher->subscribe<key_pressed_event>(this); | |||
event_dispatcher->subscribe<mouse_moved_event>(this); | |||
event_dispatcher->subscribe<mouse_wheel_scrolled_event>(this); | |||
event_dispatcher->subscribe<mouse_button_pressed_event>(this); | |||
event_dispatcher->subscribe<gamepad_axis_moved_event>(this); | |||
event_dispatcher->subscribe<gamepad_button_pressed_event>(this); | |||
} | |||
this->event_dispatcher = event_dispatcher; | |||
} | |||
} | |||
void listener::set_callback(std::function<void(const event_base&)> callback) | |||
{ | |||
this->callback = callback; | |||
} | |||
void listener::set_enabled(bool enabled) | |||
{ | |||
this->enabled = enabled; | |||
} | |||
void listener::handle_event(const key_pressed_event& event) | |||
{ | |||
if (enabled && callback) | |||
callback(event); | |||
} | |||
void listener::handle_event(const mouse_moved_event& event) | |||
{ | |||
if (enabled && callback) | |||
callback(event); | |||
} | |||
void listener::handle_event(const mouse_button_pressed_event& event) | |||
{ | |||
if (enabled && callback) | |||
callback(event); | |||
} | |||
void listener::handle_event(const mouse_wheel_scrolled_event& event) | |||
{ | |||
if (enabled && callback) | |||
callback(event); | |||
} | |||
void listener::handle_event(const gamepad_button_pressed_event& event) | |||
{ | |||
if (enabled && callback) | |||
callback(event); | |||
} | |||
void listener::handle_event(const gamepad_axis_moved_event& event) | |||
{ | |||
if (enabled && callback) | |||
callback(event); | |||
} | |||
} // namespace input |
@ -1,97 +0,0 @@ | |||
/* | |||
* Copyright (C) 2023 Christopher J. Howard | |||
* | |||
* This file is part of Antkeeper source code. | |||
* | |||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation, either version 3 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* Antkeeper source code is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License | |||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | |||
#ifndef ANTKEEPER_INPUT_LISTENER_HPP | |||
#define ANTKEEPER_INPUT_LISTENER_HPP | |||
#include "event/input-events.hpp" | |||
#include "event/event-handler.hpp" | |||
#include "event/event-dispatcher.hpp" | |||
#include <functional> | |||
namespace input { | |||
/** | |||
* Listens for all types of input events. | |||
*/ | |||
class listener: | |||
public event_handler<key_pressed_event>, | |||
public event_handler<mouse_moved_event>, | |||
public event_handler<mouse_wheel_scrolled_event>, | |||
public event_handler<mouse_button_pressed_event>, | |||
public event_handler<gamepad_axis_moved_event>, | |||
public event_handler<gamepad_button_pressed_event> | |||
{ | |||
public: | |||
/** | |||
* Creates an input listener. | |||
*/ | |||
listener(); | |||
/** | |||
* Destroys an input listener. | |||
*/ | |||
virtual ~listener(); | |||
/** | |||
* Sets the event dispatcher to which this input event router will subscribe itself. | |||
*/ | |||
void set_event_dispatcher(event_dispatcher* event_dispatcher); | |||
/** | |||
* Sets the input event callback function. | |||
* | |||
* @param callback Callback function which operates on an input event. | |||
*/ | |||
void set_callback(std::function<void(const event_base&)> event); | |||
/** | |||
* Enables or disables the input listening. | |||
* | |||
* @param enabled Whether to enable input listening or not. | |||
*/ | |||
void set_enabled(bool enabled); | |||
/** | |||
* Returns true if input listening is enabled. | |||
*/ | |||
bool is_enabled() const; | |||
private: | |||
void handle_event(const key_pressed_event& event); | |||
void handle_event(const mouse_moved_event& event); | |||
void handle_event(const mouse_wheel_scrolled_event& event); | |||
void handle_event(const mouse_button_pressed_event& event); | |||
void handle_event(const gamepad_axis_moved_event& event); | |||
void handle_event(const gamepad_button_pressed_event& event); | |||
event_dispatcher* event_dispatcher; | |||
std::function<void(const event_base&)> callback; | |||
bool enabled; | |||
}; | |||
inline bool listener::is_enabled() const | |||
{ | |||
return enabled; | |||
} | |||
} // namespace input | |||
#endif // ANTKEEPER_INPUT_LISTENER_HPP | |||
@ -0,0 +1,90 @@ | |||
/* | |||
* Copyright (C) 2023 Christopher J. Howard | |||
* | |||
* This file is part of Antkeeper source code. | |||
* | |||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation, either version 3 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* Antkeeper source code is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License | |||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | |||
#ifndef ANTKEEPER_INPUT_MODIFIER_KEY_HPP | |||
#define ANTKEEPER_INPUT_MODIFIER_KEY_HPP | |||
#include <cstdint> | |||
namespace input { | |||
/** | |||
* Modifier key bit mask flags. | |||
*/ | |||
namespace modifier_key { | |||
/// Modifier key bit flags. | |||
enum: std::uint16_t | |||
{ | |||
/// No modifier key is pressed. | |||
none = 0b0000000000000000, | |||
/// Left shift modifier key is pressed. | |||
left_shift = 0b0000000000000001, | |||
/// Right shift modifier key is pressed. | |||
right_shift = 0b0000000000000010, | |||
/// One or both shift modifier keys are pressed. | |||
shift = left_shift | right_shift, | |||
/// Left ctrl modifier key is pressed. | |||
left_ctrl = 0b0000000000000100, | |||
/// Right ctrl modifier key is pressed. | |||
right_ctrl = 0b0000000000001000, | |||
/// One or both ctrl modifier keys are pressed. | |||
ctrl = left_ctrl | right_ctrl, | |||
/// Left alt modifier key is pressed. | |||
left_alt = 0b0000000000010000, | |||
/// Right alt modifier key is pressed. | |||
right_alt = 0b0000000000100000, | |||
/// One or both alt modifier keys are pressed. | |||
alt = left_alt | right_alt, | |||
/// Left gui modifier key is pressed. | |||
left_gui = 0b0000000001000000, | |||
/// Right gui modifier key is pressed. | |||
right_gui = 0b0000000010000000, | |||
/// One or both gui modifier keys are pressed. | |||
gui = left_gui | right_gui, | |||
/// Num lock modifier key is pressed. | |||
num_lock = 0b0000000100000000, | |||
/// Caps lock modifier key is pressed. | |||
caps_lock = 0b0000001000000000, | |||
/// Scroll lock modifier key is pressed. | |||
scroll_lock = 0b0000010000000000, | |||
/// AltGr modifier key is pressed. | |||
alt_gr = 0b0000100000000000 | |||
}; | |||
} // namespace modifier_key | |||
} // namespace input | |||
#endif // ANTKEEPER_INPUT_MODIFIER_KEY_HPP |
@ -0,0 +1,42 @@ | |||
/* | |||
* Copyright (C) 2023 Christopher J. Howard | |||
* | |||
* This file is part of Antkeeper source code. | |||
* | |||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||
* it under the terms of the GNU General Public License as published by | |||
* the Free Software Foundation, either version 3 of the License, or | |||
* (at your option) any later version. | |||
* | |||
* Antkeeper source code is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU General Public License | |||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | |||
#ifndef ANTKEEPER_INPUT_MOUSE_BUTTON_HPP | |||
#define ANTKEEPER_INPUT_MOUSE_BUTTON_HPP | |||
#include <cstdint> | |||
namespace input { | |||
/// Mouse buttons. | |||
enum class mouse_button: std::uint8_t | |||
{ | |||
/// Left mouse button. | |||
left = 1, | |||
/// Middle mouse button. | |||
middle = 2, | |||
/// Right mouse button. | |||
right = 3 | |||
}; | |||
} // namespace input | |||
#endif // ANTKEEPER_INPUT_MOUSE_BUTTON_HPP |