diff --git a/CMakeLists.txt b/CMakeLists.txt
index af368e1..d4aa351 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,6 +1,5 @@
cmake_minimum_required(VERSION 3.7)
-
option(VERSION_STRING "Project version string" "0.0.0")
project(antkeeper VERSION ${VERSION_STRING} LANGUAGES CXX)
diff --git a/src/application.cpp b/src/application.cpp
index ee7cc35..88f4a64 100644
--- a/src/application.cpp
+++ b/src/application.cpp
@@ -654,14 +654,27 @@ void application::translate_sdl_events()
}
else
{
- logger->log("Connected gamepad \"" + controller_name + "\"");
+ // Get gamepad GUID
+ SDL_Joystick* sdl_joystick = SDL_GameControllerGetJoystick(sdl_controller);
+ SDL_JoystickGUID sdl_guid = SDL_JoystickGetGUID(sdl_joystick);
+ char guid_buffer[33];
+ std::memset(guid_buffer, '\0', 33);
+ SDL_JoystickGetGUIDString(sdl_guid, &guid_buffer[0], 33);
+ std::string guid(guid_buffer);
- input::gamepad* controller = new input::gamepad();
- controller->set_event_dispatcher(event_dispatcher);
- gamepads.push_back(controller);
- gamepad_map[sdl_event.cdevice.which] = controller;
+ logger->log("Connected gamepad \"" + controller_name + "\" with GUID: " + guid + "");
- controller->connect(false);
+ // Create new gamepad
+ input::gamepad* gamepad = new input::gamepad();
+ gamepad->set_event_dispatcher(event_dispatcher);
+ gamepad->set_guid(guid);
+
+ // Add gamepad to list and map
+ gamepads.push_back(gamepad);
+ gamepad_map[sdl_event.cdevice.which] = gamepad;
+
+ // Send controller connected event
+ gamepad->connect(false);
}
}
else
diff --git a/src/game/bootloader.cpp b/src/game/bootloader.cpp
index 5f658b3..c204975 100644
--- a/src/game/bootloader.cpp
+++ b/src/game/bootloader.cpp
@@ -250,6 +250,7 @@ void setup_resources(game::context* ctx)
ctx->mods_path = ctx->config_path + "mods/";
ctx->saves_path = ctx->config_path + "saves/";
ctx->screenshots_path = ctx->config_path + "screenshots/";
+ ctx->controls_path = ctx->config_path + "controls/";
// Log resource paths
logger->log("Detected data path as \"" + ctx->data_path + "\"");
@@ -261,6 +262,7 @@ void setup_resources(game::context* ctx)
config_paths.push_back(ctx->mods_path);
config_paths.push_back(ctx->saves_path);
config_paths.push_back(ctx->screenshots_path);
+ config_paths.push_back(ctx->controls_path);
for (const std::string& path: config_paths)
{
if (!path_exists(path))
diff --git a/src/game/context.hpp b/src/game/context.hpp
index b999ba6..ed4b0d6 100644
--- a/src/game/context.hpp
+++ b/src/game/context.hpp
@@ -126,6 +126,7 @@ struct context
std::string mods_path;
std::string saves_path;
std::string screenshots_path;
+ std::string controls_path;
std::string data_package_path;
// Configuration
diff --git a/src/game/controls.cpp b/src/game/controls.cpp
new file mode 100644
index 0000000..8f316d4
--- /dev/null
+++ b/src/game/controls.cpp
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2021 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 .
+ */
+
+#include "controls.hpp"
+#include "resources/resource-manager.hpp"
+#include
+
+namespace game {
+
+std::string gamepad_calibration_path(const game::context* ctx, const input::gamepad* gamepad)
+{
+ return "gamepad-" + gamepad->get_guid() + ".json";
+}
+
+json default_gamepad_calibration()
+{
+ const float activation_min = 0.15f;
+ const float activation_max = 0.98f;
+ const bool deadzone_cross = false;
+ const float deadzone_roundness = 1.0f;
+ const std::string response_curve = "linear";
+
+ json calibration;
+
+ calibration["leftx_activation"] = {activation_min, activation_max};
+ calibration["lefty_activation"] = {activation_min, activation_max};
+ calibration["rightx_activation"] = {activation_min, activation_max};
+ calibration["righty_activation"] = {activation_min, activation_max};
+ calibration["lefttrigger_activation"] = {activation_min, activation_max};
+ calibration["righttrigger_activation"] = {activation_min, activation_max};
+ calibration["leftx_response_curve"] = response_curve;
+ calibration["lefty_response_curve"] = response_curve;
+ calibration["rightx_response_curve"] = response_curve;
+ calibration["righty_response_curve"] = response_curve;
+ calibration["lefttrigger_response_curve"] = response_curve;
+ calibration["righttrigger_response_curve"] = response_curve;
+ calibration["left_deadzone_cross"] = deadzone_cross;
+ calibration["right_deadzone_cross"] = deadzone_cross;
+ calibration["left_deadzone_roundness"] = deadzone_roundness;
+ calibration["right_deadzone_roundness"] = deadzone_roundness;
+
+ return calibration;
+}
+
+json* load_gamepad_calibration(game::context* ctx, input::gamepad* gamepad)
+{
+ // Determine path to gamepad calibration file
+ std::string filepath = gamepad_calibration_path(ctx, gamepad);
+
+ // Load gamepad calibration file
+ json* calibration = ctx->resource_manager->load(filepath);
+
+ return calibration;
+}
+
+bool save_gamepad_calibration(const game::context* ctx, const input::gamepad* gamepad, const json& calibration)
+{
+ // Determine path to gamepad calibration file
+ std::string filepath = ctx->controls_path + gamepad_calibration_path(ctx, gamepad);
+
+ // Open calibration file
+ std::ofstream stream;
+ stream.open(filepath);
+ if (!stream)
+ return false;
+
+ // Write calibration to file
+ stream << calibration.dump(1, '\t');
+ if (stream.bad())
+ {
+ stream.close();
+ return false;
+ }
+
+ // Close calibration file
+ stream.close();
+
+ return true;
+}
+
+void apply_gamepad_calibration(input::gamepad* gamepad, const json& calibration)
+{
+ // Parse and apply activation thresholds
+ if (calibration.contains("leftx_activation"))
+ {
+ float min = calibration["leftx_activation"][0].get();
+ float max = calibration["leftx_activation"][1].get();
+ gamepad->set_activation_threshold(input::gamepad_axis::left_x, min, max);
+ }
+ if (calibration.contains("lefty_activation"))
+ {
+ float min = calibration["lefty_activation"][0].get();
+ float max = calibration["lefty_activation"][1].get();
+ gamepad->set_activation_threshold(input::gamepad_axis::left_y, min, max);
+ }
+ if (calibration.contains("rightx_activation"))
+ {
+ float min = calibration["rightx_activation"][0].get();
+ float max = calibration["rightx_activation"][1].get();
+ gamepad->set_activation_threshold(input::gamepad_axis::right_x, min, max);
+ }
+ if (calibration.contains("righty_activation"))
+ {
+ float min = calibration["righty_activation"][0].get();
+ float max = calibration["righty_activation"][1].get();
+ gamepad->set_activation_threshold(input::gamepad_axis::right_y, min, max);
+ }
+ if (calibration.contains("lefttrigger_activation"))
+ {
+ float min = calibration["lefttrigger_activation"][0].get();
+ float max = calibration["lefttrigger_activation"][1].get();
+ gamepad->set_activation_threshold(input::gamepad_axis::left_trigger, min, max);
+ }
+ if (calibration.contains("righttrigger_activation"))
+ {
+ float min = calibration["righttrigger_activation"][0].get();
+ float max = calibration["righttrigger_activation"][1].get();
+ gamepad->set_activation_threshold(input::gamepad_axis::right_trigger, min, max);
+ }
+
+ // Parse and apply deadzone shapes
+ if (calibration.contains("left_deadzone_cross"))
+ gamepad->set_left_deadzone_cross(calibration["left_deadzone_cross"].get());
+ if (calibration.contains("right_deadzone_cross"))
+ gamepad->set_right_deadzone_cross(calibration["right_deadzone_cross"].get());
+ if (calibration.contains("left_deadzone_roundness"))
+ gamepad->set_left_deadzone_roundness(calibration["left_deadzone_roundness"].get());
+ if (calibration.contains("right_deadzone_roundness"))
+ gamepad->set_right_deadzone_roundness(calibration["right_deadzone_roundness"].get());
+
+ auto parse_response_curve = [](const std::string& curve) -> input::gamepad_response_curve
+ {
+ if (curve == "square")
+ return input::gamepad_response_curve::square;
+ else if (curve == "cube")
+ return input::gamepad_response_curve::cube;
+ return input::gamepad_response_curve::linear;
+ };
+
+ // Parse and apply axis response curves
+ if (calibration.contains("leftx_response_curve"))
+ {
+ auto curve = parse_response_curve(calibration["leftx_response_curve"].get());
+ gamepad->set_response_curve(input::gamepad_axis::left_x, curve);
+ }
+ if (calibration.contains("lefty_response_curve"))
+ {
+ auto curve = parse_response_curve(calibration["lefty_response_curve"].get());
+ gamepad->set_response_curve(input::gamepad_axis::left_y, curve);
+ }
+ if (calibration.contains("rightx_response_curve"))
+ {
+ auto curve = parse_response_curve(calibration["rightx_response_curve"].get());
+ gamepad->set_response_curve(input::gamepad_axis::right_x, curve);
+ }
+ if (calibration.contains("righty_response_curve"))
+ {
+ auto curve = parse_response_curve(calibration["righty_response_curve"].get());
+ gamepad->set_response_curve(input::gamepad_axis::right_y, curve);
+ }
+ if (calibration.contains("lefttrigger_response_curve"))
+ {
+ auto curve = parse_response_curve(calibration["lefttrigger_response_curve"].get());
+ gamepad->set_response_curve(input::gamepad_axis::left_trigger, curve);
+ }
+ if (calibration.contains("righttrigger_response_curve"))
+ {
+ auto curve = parse_response_curve(calibration["righttrigger_response_curve"].get());
+ gamepad->set_response_curve(input::gamepad_axis::right_trigger, curve);
+ }
+}
+
+} // namespace game
diff --git a/src/game/controls.hpp b/src/game/controls.hpp
new file mode 100644
index 0000000..f35ed9f
--- /dev/null
+++ b/src/game/controls.hpp
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2021 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 .
+ */
+
+#ifndef ANTKEEPER_GAME_CONTROLS_HPP
+#define ANTKEEPER_GAME_CONTROLS_HPP
+
+#include "game/context.hpp"
+#include "resources/json.hpp"
+#include "input/gamepad.hpp"
+
+namespace game {
+
+/**
+ * Returns a string containing the path to the gamepad calibration file.
+ */
+std::string gamepad_calibration_path(const game::context* ctx, const input::gamepad* gamepad);
+
+/**
+ * Generates default gamepad calibration settings.
+ *
+ * @return Default gamepad calibration settings.
+ */
+json default_gamepad_calibration();
+
+/**
+ * Loads gamepad calibration settings.
+ *
+ * @param ctx Game context.
+ * @param gamepad Gamepad for which to load calibration settings.
+ */
+json* load_gamepad_calibration(game::context* ctx, input::gamepad* gamepad);
+
+/**
+ * Saves gamepad calibration settings.
+ *
+ * @param ctx Game context.
+ * @param gamepad Gamepad for which to save calibration settings.
+ * @return `true` if calibration settings were successfully saved, `false` otherwise.
+ */
+bool save_gamepad_calibration(const game::context* ctx, const input::gamepad* gamepad, const json& calibration);
+
+/**
+ * Applies gamepad calibration settings.
+ *
+ * @param gamepad Gamepad to calibrate.
+ * @param calibration JSON element containing gamepad calibration settings.
+ */
+void apply_gamepad_calibration(input::gamepad* gamepad, const json& calibration);
+
+} // namespace game
+
+#endif // ANTKEEPER_GAME_CONTROLS_HPP
diff --git a/src/game/states/loading.cpp b/src/game/states/loading.cpp
index 096885e..07419bd 100644
--- a/src/game/states/loading.cpp
+++ b/src/game/states/loading.cpp
@@ -30,9 +30,11 @@
#include "entity/systems/astronomy.hpp"
#include "entity/systems/orbit.hpp"
#include "entity/commands.hpp"
+#include "entity/archetype.hpp"
#include "game/states/nuptial-flight.hpp"
#include "game/states/splash.hpp"
#include "game/states/forage.hpp"
+#include "game/controls.hpp"
#include "geom/spherical.hpp"
#include "gl/drawing-mode.hpp"
#include "gl/vertex-array.hpp"
@@ -56,8 +58,6 @@ namespace loading {
/// Creates or loads control configuration
static void load_controls(game::context* ctx);
-static input::gamepad_response_curve parse_response_curve(const std::string& curve);
-
/// Creates the universe and solar system.
static void cosmogenesis(game::context* ctx);
@@ -379,93 +379,28 @@ void load_controls(game::context* ctx)
}
}
- // Set gamepad deadzones
- float gamepad_leftx_activation_min = 0.0f;
- float gamepad_leftx_activation_max = 0.0f;
- float gamepad_lefty_activation_min = 0.0f;
- float gamepad_lefty_activation_max = 0.0f;
- float gamepad_rightx_activation_min = 0.0f;
- float gamepad_rightx_activation_max = 0.0f;
- float gamepad_righty_activation_min = 0.0f;
- float gamepad_righty_activation_max = 0.0f;
- float gamepad_lefttrigger_activation_min = 0.0f;
- float gamepad_lefttrigger_activation_max = 0.0f;
- float gamepad_righttrigger_activation_min = 0.0f;
- float gamepad_righttrigger_activation_max = 0.0f;
- bool gamepad_left_deadzone_cross = true;
- bool gamepad_right_deadzone_cross = true;
- float gamepad_left_deadzone_roundness = 0.0f;
- float gamepad_right_deadzone_roundness = 0.0f;
- input::gamepad_response_curve gamepad_leftx_response_curve = input::gamepad_response_curve::linear;
- input::gamepad_response_curve gamepad_lefty_response_curve = input::gamepad_response_curve::linear;
- input::gamepad_response_curve gamepad_rightx_response_curve = input::gamepad_response_curve::linear;
- input::gamepad_response_curve gamepad_righty_response_curve = input::gamepad_response_curve::linear;
- input::gamepad_response_curve gamepad_lefttrigger_response_curve = input::gamepad_response_curve::linear;
- input::gamepad_response_curve gamepad_righttrigger_response_curve = input::gamepad_response_curve::linear;
-
- if (ctx->config->contains("gamepad_leftx_activation_min"))
- gamepad_leftx_activation_min = (*ctx->config)["gamepad_leftx_activation_min"].get();
- if (ctx->config->contains("gamepad_leftx_activation_max"))
- gamepad_leftx_activation_max = (*ctx->config)["gamepad_leftx_activation_max"].get();
- if (ctx->config->contains("gamepad_lefty_activation_min"))
- gamepad_lefty_activation_min = (*ctx->config)["gamepad_lefty_activation_min"].get();
- if (ctx->config->contains("gamepad_lefty_activation_max"))
- gamepad_lefty_activation_max = (*ctx->config)["gamepad_lefty_activation_max"].get();
- if (ctx->config->contains("gamepad_rightx_activation_min"))
- gamepad_rightx_activation_min = (*ctx->config)["gamepad_rightx_activation_min"].get();
- if (ctx->config->contains("gamepad_rightx_activation_max"))
- gamepad_rightx_activation_max = (*ctx->config)["gamepad_rightx_activation_max"].get();
- if (ctx->config->contains("gamepad_righty_activation_min"))
- gamepad_righty_activation_min = (*ctx->config)["gamepad_righty_activation_min"].get();
- if (ctx->config->contains("gamepad_righty_activation_max"))
- gamepad_righty_activation_max = (*ctx->config)["gamepad_righty_activation_max"].get();
- if (ctx->config->contains("gamepad_lefttrigger_activation_min"))
- gamepad_lefttrigger_activation_min = (*ctx->config)["gamepad_lefttrigger_activation_min"].get();
- if (ctx->config->contains("gamepad_lefttrigger_activation_max"))
- gamepad_lefttrigger_activation_max = (*ctx->config)["gamepad_lefttrigger_activation_max"].get();
- if (ctx->config->contains("gamepad_righttrigger_activation_min"))
- gamepad_righttrigger_activation_min = (*ctx->config)["gamepad_righttrigger_activation_min"].get();
- if (ctx->config->contains("gamepad_righttrigger_activation_max"))
- gamepad_righttrigger_activation_max = (*ctx->config)["gamepad_righttrigger_activation_max"].get();
- if (ctx->config->contains("gamepad_left_deadzone_cross"))
- gamepad_left_deadzone_cross = (*ctx->config)["gamepad_left_deadzone_cross"].get();
- if (ctx->config->contains("gamepad_right_deadzone_cross"))
- gamepad_right_deadzone_cross = (*ctx->config)["gamepad_right_deadzone_cross"].get();
- if (ctx->config->contains("gamepad_left_deadzone_roundness"))
- gamepad_left_deadzone_roundness = (*ctx->config)["gamepad_left_deadzone_roundness"].get();
- if (ctx->config->contains("gamepad_right_deadzone_roundness"))
- gamepad_right_deadzone_roundness = (*ctx->config)["gamepad_right_deadzone_roundness"].get();
- if (ctx->config->contains("gamepad_leftx_response_curve"))
- gamepad_leftx_response_curve = parse_response_curve((*ctx->config)["gamepad_leftx_response_curve"].get());
- if (ctx->config->contains("gamepad_leftx_response_curve"))
- gamepad_leftx_response_curve = parse_response_curve((*ctx->config)["gamepad_leftx_response_curve"].get());
- if (ctx->config->contains("gamepad_rightx_response_curve"))
- gamepad_rightx_response_curve = parse_response_curve((*ctx->config)["gamepad_rightx_response_curve"].get());
- if (ctx->config->contains("gamepad_leftx_response_curve"))
- gamepad_leftx_response_curve = parse_response_curve((*ctx->config)["gamepad_leftx_response_curve"].get());
- if (ctx->config->contains("gamepad_lefttrigger_response_curve"))
- gamepad_lefttrigger_response_curve = parse_response_curve((*ctx->config)["gamepad_lefttrigger_response_curve"].get());
- if (ctx->config->contains("gamepad_righttrigger_response_curve"))
- gamepad_righttrigger_response_curve = parse_response_curve((*ctx->config)["gamepad_righttrigger_response_curve"].get());
-
for (input::gamepad* gamepad: ctx->app->get_gamepads())
{
- gamepad->set_activation_threshold(input::gamepad_axis::left_x, gamepad_leftx_activation_min, gamepad_leftx_activation_max);
- gamepad->set_activation_threshold(input::gamepad_axis::left_y, gamepad_lefty_activation_min, gamepad_lefty_activation_max);
- gamepad->set_activation_threshold(input::gamepad_axis::right_x, gamepad_rightx_activation_min, gamepad_rightx_activation_max);
- gamepad->set_activation_threshold(input::gamepad_axis::right_y, gamepad_righty_activation_min, gamepad_righty_activation_max);
- gamepad->set_activation_threshold(input::gamepad_axis::left_trigger, gamepad_lefttrigger_activation_min, gamepad_lefttrigger_activation_max);
- gamepad->set_activation_threshold(input::gamepad_axis::right_trigger, gamepad_righttrigger_activation_min, gamepad_righttrigger_activation_max);
- gamepad->set_left_deadzone_cross(gamepad_left_deadzone_cross);
- gamepad->set_right_deadzone_cross(gamepad_right_deadzone_cross);
- gamepad->set_left_deadzone_roundness(gamepad_left_deadzone_roundness);
- gamepad->set_right_deadzone_roundness(gamepad_right_deadzone_roundness);
- gamepad->set_response_curve(input::gamepad_axis::left_x, gamepad_leftx_response_curve);
- gamepad->set_response_curve(input::gamepad_axis::left_y, gamepad_lefty_response_curve);
- gamepad->set_response_curve(input::gamepad_axis::right_x, gamepad_rightx_response_curve);
- gamepad->set_response_curve(input::gamepad_axis::right_y, gamepad_righty_response_curve);
- gamepad->set_response_curve(input::gamepad_axis::left_trigger, gamepad_lefttrigger_response_curve);
- gamepad->set_response_curve(input::gamepad_axis::right_trigger, gamepad_righttrigger_response_curve);
+ ctx->logger->push_task("Loading calibration for gamepad " + gamepad->get_guid());
+ json* calibration = game::load_gamepad_calibration(ctx, gamepad);
+ if (!calibration)
+ {
+ ctx->logger->pop_task(EXIT_FAILURE);
+
+ ctx->logger->push_task("Generating default calibration for gamepad " + gamepad->get_guid());
+ json default_calibration = game::default_gamepad_calibration();
+ apply_gamepad_calibration(gamepad, default_calibration);
+
+ if (!save_gamepad_calibration(ctx, gamepad, default_calibration))
+ ctx->logger->pop_task(EXIT_FAILURE);
+ else
+ ctx->logger->pop_task(EXIT_SUCCESS);
+ }
+ else
+ {
+ ctx->logger->pop_task(EXIT_SUCCESS);
+ apply_gamepad_calibration(gamepad, *calibration);
+ }
}
// Toggle fullscreen
@@ -507,15 +442,6 @@ void load_controls(game::context* ctx)
);
}
-static input::gamepad_response_curve parse_response_curve(const std::string& curve)
-{
- if (curve == "square")
- return input::gamepad_response_curve::square;
- else if (curve == "cube")
- return input::gamepad_response_curve::cube;
- return input::gamepad_response_curve::linear;
-}
-
void cosmogenesis(game::context* ctx)
{
// Init time
@@ -592,38 +518,10 @@ void cosmogenesis(game::context* ctx)
void heliogenesis(game::context* ctx)
{
// Create solar entity
- entity::id sun_eid = ctx->entity_registry->create();
+ entity::archetype* sun_archetype = ctx->resource_manager->load("sun.ent");
+ entity::id sun_eid = sun_archetype->create(*ctx->entity_registry);
ctx->entities["sun"] = sun_eid;
- // Assign solar celestial body component
- entity::component::celestial_body body;
- body.radius = 6.957e+8;
- body.axial_tilt = math::radians(0.0);
- body.axial_rotation = math::radians(0.0);
- body.angular_frequency = math::radians(0.0);
- ctx->entity_registry->assign(sun_eid, body);
-
- // Assign solar orbit component
- entity::component::orbit orbit;
- orbit.elements.a = 0.0;
- orbit.elements.e = 0.0;
- orbit.elements.i = math::radians(0.0);
- orbit.elements.raan = math::radians(0.0);
- orbit.elements.w = math::radians(0.0);
- orbit.elements.ta = math::radians(0.0);
- ctx->entity_registry->assign(sun_eid, orbit);
-
- // Assign solar blackbody component
- entity::component::blackbody blackbody;
- blackbody.temperature = 5778.0;
- ctx->entity_registry->assign(sun_eid, blackbody);
-
- // Assign solar transform component
- entity::component::transform transform;
- transform.local = math::identity_transform;
- transform.warp = true;
- ctx->entity_registry->assign(sun_eid, transform);
-
// Create direct sun light scene object
scene::directional_light* sun_direct = new scene::directional_light();
diff --git a/src/input/device.cpp b/src/input/device.cpp
index 5101fe0..09bb955 100644
--- a/src/input/device.cpp
+++ b/src/input/device.cpp
@@ -30,4 +30,9 @@ void device::set_event_dispatcher(::event_dispatcher* event_dispatcher)
this->event_dispatcher = event_dispatcher;
}
+void device::set_guid(const std::string& guid)
+{
+ this->guid = guid;
+}
+
} // namespace input
diff --git a/src/input/device.hpp b/src/input/device.hpp
index a882930..883c2ed 100644
--- a/src/input/device.hpp
+++ b/src/input/device.hpp
@@ -21,6 +21,7 @@
#define ANTKEEPER_INPUT_DEVICE_HPP
#include "event/event-dispatcher.hpp"
+#include
namespace input {
@@ -36,9 +37,22 @@ public:
void set_event_dispatcher(event_dispatcher* event_dispatcher);
const event_dispatcher* get_event_dispatcher() const;
event_dispatcher* get_event_dispatcher();
+
+ /**
+ * Sets the globally unique identifier (GUID) of this input device.
+ *
+ * @param guid GUID string.
+ */
+ void set_guid(const std::string& guid);
+
+ /// Returns the globally unique identifier (GUID) of this input device.
+ const std::string& get_guid() const;
protected:
event_dispatcher* event_dispatcher;
+
+private:
+ std::string guid;
};
inline const event_dispatcher* device::get_event_dispatcher() const
@@ -51,6 +65,11 @@ inline event_dispatcher* device::get_event_dispatcher()
return event_dispatcher;
}
+inline const std::string& device::get_guid() const
+{
+ return guid;
+}
+
} // namespace input
#endif // ANTKEEPER_INPUT_DEVICE_HPP