summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/common/CMakeLists.txt1
-rw-r--r--src/common/input.h242
2 files changed, 243 insertions, 0 deletions
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index 23d43a394..919da4a53 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -73,6 +73,7 @@ add_library(common STATIC
hex_util.h
host_memory.cpp
host_memory.h
+ input.h
intrusive_red_black_tree.h
literals.h
logging/backend.cpp
diff --git a/src/common/input.h b/src/common/input.h
new file mode 100644
index 000000000..6eefc55f9
--- /dev/null
+++ b/src/common/input.h
@@ -0,0 +1,242 @@
+// Copyright 2017 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <functional>
+#include <memory>
+#include <string>
+#include <unordered_map>
+#include <utility>
+#include "common/logging/log.h"
+#include "common/param_package.h"
+
+namespace Input {
+
+enum class InputType {
+ None,
+ Battery,
+ Button,
+ Stick,
+ Analog,
+ Trigger,
+ Motion,
+ Touch,
+ Color,
+ Vibration,
+ Nfc,
+ Ir,
+};
+
+enum class BatteryLevel {
+ Empty,
+ Critical,
+ Low,
+ Medium,
+ Full,
+ Charging,
+};
+
+struct AnalogProperties {
+ float deadzone{};
+ float range{1.0f};
+ float threshold{0.5f};
+ float offset{};
+ bool inverted{};
+};
+
+struct AnalogStatus {
+ float value{};
+ float raw_value{};
+ AnalogProperties properties{};
+};
+
+struct ButtonStatus {
+ bool value{};
+ bool inverted{};
+ bool toggle{};
+ bool locked{};
+};
+
+using BatteryStatus = BatteryLevel;
+
+struct StickStatus {
+ AnalogStatus x{};
+ AnalogStatus y{};
+ bool left{};
+ bool right{};
+ bool up{};
+ bool down{};
+};
+
+struct TriggerStatus {
+ AnalogStatus analog{};
+ bool pressed{};
+};
+
+struct MotionSensor {
+ AnalogStatus x{};
+ AnalogStatus y{};
+ AnalogStatus z{};
+};
+
+struct MotionStatus {
+ MotionSensor gyro{};
+ MotionSensor accel{};
+ u64 delta_timestamp{};
+};
+
+struct TouchStatus {
+ ButtonStatus pressed{};
+ AnalogStatus x{};
+ AnalogStatus y{};
+ u32 id{};
+};
+
+struct BodyColorStatus {
+ u32 body{};
+ u32 buttons{};
+};
+
+struct VibrationStatus {
+ f32 low_amplitude{};
+ f32 low_frequency{};
+ f32 high_amplitude{};
+ f32 high_frequency{};
+};
+
+struct LedStatus {
+ bool led_1{};
+ bool led_2{};
+ bool led_3{};
+ bool led_4{};
+};
+
+struct CallbackStatus {
+ InputType type{InputType::None};
+ ButtonStatus button_status{};
+ StickStatus stick_status{};
+ AnalogStatus analog_status{};
+ TriggerStatus trigger_status{};
+ MotionStatus motion_status{};
+ TouchStatus touch_status{};
+ BodyColorStatus color_status{};
+ BatteryStatus battery_status{};
+ VibrationStatus vibration_status{};
+};
+
+struct InputCallback {
+ std::function<void(CallbackStatus)> on_change;
+};
+
+/// An abstract class template for an input device (a button, an analog input, etc.).
+class InputDevice {
+public:
+ virtual ~InputDevice() = default;
+
+ void SetCallback(InputCallback callback_) {
+ callback = std::move(callback_);
+ }
+
+ void TriggerOnChange(CallbackStatus status) {
+ if (callback.on_change) {
+ callback.on_change(status);
+ }
+ }
+
+private:
+ InputCallback callback;
+};
+
+/// An abstract class template for a factory that can create input devices.
+template <typename InputDeviceType>
+class Factory {
+public:
+ virtual ~Factory() = default;
+ virtual std::unique_ptr<InputDeviceType> Create(const Common::ParamPackage&) = 0;
+};
+
+namespace Impl {
+
+template <typename InputDeviceType>
+using FactoryListType = std::unordered_map<std::string, std::shared_ptr<Factory<InputDeviceType>>>;
+
+template <typename InputDeviceType>
+struct FactoryList {
+ static FactoryListType<InputDeviceType> list;
+};
+
+template <typename InputDeviceType>
+FactoryListType<InputDeviceType> FactoryList<InputDeviceType>::list;
+
+} // namespace Impl
+
+/**
+ * Registers an input device factory.
+ * @tparam InputDeviceType the type of input devices the factory can create
+ * @param name the name of the factory. Will be used to match the "engine" parameter when creating
+ * a device
+ * @param factory the factory object to register
+ */
+template <typename InputDeviceType>
+void RegisterFactory(const std::string& name, std::shared_ptr<Factory<InputDeviceType>> factory) {
+ auto pair = std::make_pair(name, std::move(factory));
+ if (!Impl::FactoryList<InputDeviceType>::list.insert(std::move(pair)).second) {
+ LOG_ERROR(Input, "Factory '{}' already registered", name);
+ }
+}
+
+/**
+ * Unregisters an input device factory.
+ * @tparam InputDeviceType the type of input devices the factory can create
+ * @param name the name of the factory to unregister
+ */
+template <typename InputDeviceType>
+void UnregisterFactory(const std::string& name) {
+ if (Impl::FactoryList<InputDeviceType>::list.erase(name) == 0) {
+ LOG_ERROR(Input, "Factory '{}' not registered", name);
+ }
+}
+
+/**
+ * Create an input device from given paramters.
+ * @tparam InputDeviceType the type of input devices to create
+ * @param params a serialized ParamPackage string that contains all parameters for creating the
+ * device
+ */
+template <typename InputDeviceType>
+std::unique_ptr<InputDeviceType> CreateDeviceFromString(const std::string& params) {
+ const Common::ParamPackage package(params);
+ const std::string engine = package.Get("engine", "null");
+ const auto& factory_list = Impl::FactoryList<InputDeviceType>::list;
+ const auto pair = factory_list.find(engine);
+ if (pair == factory_list.end()) {
+ if (engine != "null") {
+ LOG_ERROR(Input, "Unknown engine name: {}", engine);
+ }
+ return std::make_unique<InputDeviceType>();
+ }
+ return pair->second->Create(package);
+}
+
+/**
+ * Create an input device from given paramters.
+ * @tparam InputDeviceType the type of input devices to create
+ * @param A ParamPackage that contains all parameters for creating the device
+ */
+template <typename InputDeviceType>
+std::unique_ptr<InputDeviceType> CreateDevice(const Common::ParamPackage package) {
+ const std::string engine = package.Get("engine", "null");
+ const auto& factory_list = Impl::FactoryList<InputDeviceType>::list;
+ const auto pair = factory_list.find(engine);
+ if (pair == factory_list.end()) {
+ if (engine != "null") {
+ LOG_ERROR(Input, "Unknown engine name: {}", engine);
+ }
+ return std::make_unique<InputDeviceType>();
+ }
+ return pair->second->Create(package);
+}
+
+} // namespace Input