input.h 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. // Copyright 2017 Citra Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #pragma once
  5. #include <functional>
  6. #include <memory>
  7. #include <string>
  8. #include <tuple>
  9. #include <unordered_map>
  10. #include <utility>
  11. #include "common/logging/log.h"
  12. #include "common/param_package.h"
  13. #include "common/quaternion.h"
  14. #include "common/vector_math.h"
  15. namespace Input {
  16. enum class AnalogDirection : u8 {
  17. RIGHT,
  18. LEFT,
  19. UP,
  20. DOWN,
  21. };
  22. struct AnalogProperties {
  23. float deadzone;
  24. float range;
  25. float threshold;
  26. };
  27. template <typename StatusType>
  28. struct InputCallback {
  29. std::function<void(StatusType)> on_change;
  30. };
  31. /// An abstract class template for an input device (a button, an analog input, etc.).
  32. template <typename StatusType>
  33. class InputDevice {
  34. public:
  35. virtual ~InputDevice() = default;
  36. virtual StatusType GetStatus() const {
  37. return {};
  38. }
  39. virtual StatusType GetRawStatus() const {
  40. return GetStatus();
  41. }
  42. virtual AnalogProperties GetAnalogProperties() const {
  43. return {};
  44. }
  45. virtual bool GetAnalogDirectionStatus([[maybe_unused]] AnalogDirection direction) const {
  46. return {};
  47. }
  48. virtual bool SetRumblePlay([[maybe_unused]] f32 amp_low, [[maybe_unused]] f32 freq_low,
  49. [[maybe_unused]] f32 amp_high,
  50. [[maybe_unused]] f32 freq_high) const {
  51. return {};
  52. }
  53. void SetCallback(InputCallback<StatusType> callback_) {
  54. callback = std::move(callback_);
  55. }
  56. void TriggerOnChange() {
  57. if (callback.on_change) {
  58. callback.on_change(GetStatus());
  59. }
  60. }
  61. private:
  62. InputCallback<StatusType> callback;
  63. };
  64. /// An abstract class template for a factory that can create input devices.
  65. template <typename InputDeviceType>
  66. class Factory {
  67. public:
  68. virtual ~Factory() = default;
  69. virtual std::unique_ptr<InputDeviceType> Create(const Common::ParamPackage&) = 0;
  70. };
  71. namespace Impl {
  72. template <typename InputDeviceType>
  73. using FactoryListType = std::unordered_map<std::string, std::shared_ptr<Factory<InputDeviceType>>>;
  74. template <typename InputDeviceType>
  75. struct FactoryList {
  76. static FactoryListType<InputDeviceType> list;
  77. };
  78. template <typename InputDeviceType>
  79. FactoryListType<InputDeviceType> FactoryList<InputDeviceType>::list;
  80. } // namespace Impl
  81. /**
  82. * Registers an input device factory.
  83. * @tparam InputDeviceType the type of input devices the factory can create
  84. * @param name the name of the factory. Will be used to match the "engine" parameter when creating
  85. * a device
  86. * @param factory the factory object to register
  87. */
  88. template <typename InputDeviceType>
  89. void RegisterFactory(const std::string& name, std::shared_ptr<Factory<InputDeviceType>> factory) {
  90. auto pair = std::make_pair(name, std::move(factory));
  91. if (!Impl::FactoryList<InputDeviceType>::list.insert(std::move(pair)).second) {
  92. LOG_ERROR(Input, "Factory '{}' already registered", name);
  93. }
  94. }
  95. /**
  96. * Unregisters an input device factory.
  97. * @tparam InputDeviceType the type of input devices the factory can create
  98. * @param name the name of the factory to unregister
  99. */
  100. template <typename InputDeviceType>
  101. void UnregisterFactory(const std::string& name) {
  102. if (Impl::FactoryList<InputDeviceType>::list.erase(name) == 0) {
  103. LOG_ERROR(Input, "Factory '{}' not registered", name);
  104. }
  105. }
  106. /**
  107. * Create an input device from given paramters.
  108. * @tparam InputDeviceType the type of input devices to create
  109. * @param params a serialized ParamPackage string contains all parameters for creating the device
  110. */
  111. template <typename InputDeviceType>
  112. std::unique_ptr<InputDeviceType> CreateDevice(const std::string& params) {
  113. const Common::ParamPackage package(params);
  114. const std::string engine = package.Get("engine", "null");
  115. const auto& factory_list = Impl::FactoryList<InputDeviceType>::list;
  116. const auto pair = factory_list.find(engine);
  117. if (pair == factory_list.end()) {
  118. if (engine != "null") {
  119. LOG_ERROR(Input, "Unknown engine name: {}", engine);
  120. }
  121. return std::make_unique<InputDeviceType>();
  122. }
  123. return pair->second->Create(package);
  124. }
  125. /**
  126. * A button device is an input device that returns bool as status.
  127. * true for pressed; false for released.
  128. */
  129. using ButtonDevice = InputDevice<bool>;
  130. /**
  131. * An analog device is an input device that returns a tuple of x and y coordinates as status. The
  132. * coordinates are within the unit circle. x+ is defined as right direction, and y+ is defined as up
  133. * direction
  134. */
  135. using AnalogDevice = InputDevice<std::tuple<float, float>>;
  136. /**
  137. * A vibration device is an input device that returns an unsigned byte as status.
  138. * It represents whether the vibration device supports vibration or not.
  139. * If the status returns 1, it supports vibration. Otherwise, it does not support vibration.
  140. */
  141. using VibrationDevice = InputDevice<u8>;
  142. /**
  143. * A motion status is an object that returns a tuple of accelerometer state vector,
  144. * gyroscope state vector, rotation state vector, orientation state matrix and quaterion state
  145. * vector.
  146. *
  147. * For both 3D vectors:
  148. * x+ is the same direction as RIGHT on D-pad.
  149. * y+ is normal to the touch screen, pointing outward.
  150. * z+ is the same direction as UP on D-pad.
  151. *
  152. * For accelerometer state vector
  153. * Units: g (gravitational acceleration)
  154. *
  155. * For gyroscope state vector:
  156. * Orientation is determined by right-hand rule.
  157. * Units: deg/sec
  158. *
  159. * For rotation state vector
  160. * Units: rotations
  161. *
  162. * For orientation state matrix
  163. * x vector
  164. * y vector
  165. * z vector
  166. *
  167. * For quaternion state vector
  168. * xyz vector
  169. * w float
  170. */
  171. using MotionStatus = std::tuple<Common::Vec3<float>, Common::Vec3<float>, Common::Vec3<float>,
  172. std::array<Common::Vec3f, 3>, Common::Quaternion<f32>>;
  173. /**
  174. * A motion device is an input device that returns a motion status object
  175. */
  176. using MotionDevice = InputDevice<MotionStatus>;
  177. /**
  178. * A touch status is an object that returns an array of 16 tuple elements of two floats and a bool.
  179. * The floats are x and y coordinates in the range 0.0 - 1.0, and the bool indicates whether it is
  180. * pressed.
  181. */
  182. using TouchStatus = std::array<std::tuple<float, float, bool>, 16>;
  183. /**
  184. * A touch device is an input device that returns a touch status object
  185. */
  186. using TouchDevice = InputDevice<TouchStatus>;
  187. /**
  188. * A mouse device is an input device that returns a tuple of two floats and four ints.
  189. * The first two floats are X and Y device coordinates of the mouse (from 0-1).
  190. * The s32s are the mouse wheel.
  191. */
  192. using MouseDevice = InputDevice<std::tuple<float, float, s32, s32>>;
  193. } // namespace Input