// 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" 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 %s already registered", name.c_str()); } } /** * 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 %s not registered", name.c_str()); } } /** * 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: %s", engine.c_str()); } 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>; } // namespace Input