diff options
Diffstat (limited to 'src/common')
| -rw-r--r-- | src/common/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | src/common/input.h | 242 | 
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 | 
