// Copyright 2017 Citra Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. #pragma once #include #include #include #include #include #include "common/logging/log.h" #include "common/param_package.h" #include "common/vector_math.h" namespace Input { /// An abstract class template for an input device (a button, an analog input, etc.). template class InputDevice { public: virtual ~InputDevice() = default; virtual StatusType GetStatus() const { return {}; } }; /// An abstract class template for a factory that can create input devices. template class Factory { public: virtual ~Factory() = default; virtual std::unique_ptr Create(const Common::ParamPackage&) = 0; }; namespace Impl { template using FactoryListType = std::unordered_map>>; template struct FactoryList { static FactoryListType list; }; template FactoryListType FactoryList::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 void RegisterFactory(const std::string& name, std::shared_ptr> factory) { auto pair = std::make_pair(name, std::move(factory)); if (!Impl::FactoryList::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 void UnregisterFactory(const std::string& name) { if (Impl::FactoryList::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 contains all parameters for creating the device */ template std::unique_ptr CreateDevice(const std::string& params) { const Common::ParamPackage package(params); const std::string engine = package.Get("engine", "null"); const auto& factory_list = Impl::FactoryList::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(); } return pair->second->Create(package); } /** * A button device is an input device that returns bool as status. * true for pressed; false for released. */ using ButtonDevice = InputDevice; /** * An analog device is an input device that returns a tuple of x and y coordinates as status. The * coordinates are within the unit circle. x+ is defined as right direction, and y+ is defined as up * direction */ using AnalogDevice = InputDevice>; /** * A motion device is an input device that returns a tuple of accelerometer state vector and * gyroscope state vector. * * For both vectors: * x+ is the same direction as LEFT on D-pad. * y+ is normal to the touch screen, pointing outward. * z+ is the same direction as UP on D-pad. * * For accelerometer state vector * Units: g (gravitational acceleration) * * For gyroscope state vector: * Orientation is determined by right-hand rule. * Units: deg/sec */ using MotionDevice = InputDevice, Math::Vec3>>; /** * A touch device is an input device that returns a tuple of two floats and a bool. The floats are * x and y coordinates in the range 0.0 - 1.0, and the bool indicates whether it is pressed. */ using TouchDevice = InputDevice>; } // namespace Input