gc_poller.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. // Copyright 2020 yuzu Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <atomic>
  5. #include <list>
  6. #include <mutex>
  7. #include <utility>
  8. #include "common/assert.h"
  9. #include "common/threadsafe_queue.h"
  10. #include "input_common/gcadapter/gc_adapter.h"
  11. #include "input_common/gcadapter/gc_poller.h"
  12. namespace InputCommon {
  13. class GCButton final : public Input::ButtonDevice {
  14. public:
  15. explicit GCButton(u32 port_, s32 button_, const GCAdapter::Adapter* adapter)
  16. : port(port_), button(button_), gcadapter(adapter) {}
  17. ~GCButton() override;
  18. bool GetStatus() const override {
  19. if (gcadapter->DeviceConnected(port)) {
  20. return (gcadapter->GetPadState(port).buttons & button) != 0;
  21. }
  22. return false;
  23. }
  24. private:
  25. const u32 port;
  26. const s32 button;
  27. const GCAdapter::Adapter* gcadapter;
  28. };
  29. class GCAxisButton final : public Input::ButtonDevice {
  30. public:
  31. explicit GCAxisButton(u32 port_, u32 axis_, float threshold_, bool trigger_if_greater_,
  32. const GCAdapter::Adapter* adapter)
  33. : port(port_), axis(axis_), threshold(threshold_), trigger_if_greater(trigger_if_greater_),
  34. gcadapter(adapter) {}
  35. bool GetStatus() const override {
  36. if (gcadapter->DeviceConnected(port)) {
  37. const float current_axis_value = gcadapter->GetPadState(port).axis_values.at(axis);
  38. const float axis_value = current_axis_value / 128.0f;
  39. if (trigger_if_greater) {
  40. // TODO: Might be worthwile to set a slider for the trigger threshold. It is
  41. // currently always set to 0.5 in configure_input_player.cpp ZL/ZR HandleClick
  42. return axis_value > threshold;
  43. }
  44. return axis_value < -threshold;
  45. }
  46. return false;
  47. }
  48. private:
  49. const u32 port;
  50. const u32 axis;
  51. float threshold;
  52. bool trigger_if_greater;
  53. const GCAdapter::Adapter* gcadapter;
  54. };
  55. GCButtonFactory::GCButtonFactory(std::shared_ptr<GCAdapter::Adapter> adapter_)
  56. : adapter(std::move(adapter_)) {}
  57. GCButton::~GCButton() = default;
  58. std::unique_ptr<Input::ButtonDevice> GCButtonFactory::Create(const Common::ParamPackage& params) {
  59. const auto button_id = params.Get("button", 0);
  60. const auto port = static_cast<u32>(params.Get("port", 0));
  61. constexpr s32 PAD_STICK_ID = static_cast<s32>(GCAdapter::PadButton::Stick);
  62. // button is not an axis/stick button
  63. if (button_id != PAD_STICK_ID) {
  64. return std::make_unique<GCButton>(port, button_id, adapter.get());
  65. }
  66. // For Axis buttons, used by the binary sticks.
  67. if (button_id == PAD_STICK_ID) {
  68. const int axis = params.Get("axis", 0);
  69. const float threshold = params.Get("threshold", 0.25f);
  70. const std::string direction_name = params.Get("direction", "");
  71. bool trigger_if_greater;
  72. if (direction_name == "+") {
  73. trigger_if_greater = true;
  74. } else if (direction_name == "-") {
  75. trigger_if_greater = false;
  76. } else {
  77. trigger_if_greater = true;
  78. LOG_ERROR(Input, "Unknown direction {}", direction_name);
  79. }
  80. return std::make_unique<GCAxisButton>(port, axis, threshold, trigger_if_greater,
  81. adapter.get());
  82. }
  83. return nullptr;
  84. }
  85. Common::ParamPackage GCButtonFactory::GetNextInput() const {
  86. Common::ParamPackage params;
  87. GCAdapter::GCPadStatus pad;
  88. auto& queue = adapter->GetPadQueue();
  89. while (queue.Pop(pad)) {
  90. // This while loop will break on the earliest detected button
  91. params.Set("engine", "gcpad");
  92. params.Set("port", static_cast<s32>(pad.port));
  93. if (pad.button != GCAdapter::PadButton::Undefined) {
  94. params.Set("button", static_cast<u16>(pad.button));
  95. }
  96. // For Axis button implementation
  97. if (pad.axis != GCAdapter::PadAxes::Undefined) {
  98. params.Set("axis", static_cast<u8>(pad.axis));
  99. params.Set("button", static_cast<u16>(GCAdapter::PadButton::Stick));
  100. params.Set("threshold", "0.25");
  101. if (pad.axis_value > 0) {
  102. params.Set("direction", "+");
  103. } else {
  104. params.Set("direction", "-");
  105. }
  106. break;
  107. }
  108. }
  109. return params;
  110. }
  111. void GCButtonFactory::BeginConfiguration() {
  112. polling = true;
  113. adapter->BeginConfiguration();
  114. }
  115. void GCButtonFactory::EndConfiguration() {
  116. polling = false;
  117. adapter->EndConfiguration();
  118. }
  119. class GCAnalog final : public Input::AnalogDevice {
  120. public:
  121. explicit GCAnalog(u32 port_, u32 axis_x_, u32 axis_y_, float deadzone_,
  122. const GCAdapter::Adapter* adapter, float range_)
  123. : port(port_), axis_x(axis_x_), axis_y(axis_y_), deadzone(deadzone_), gcadapter(adapter),
  124. range(range_) {}
  125. float GetAxis(u32 axis) const {
  126. if (gcadapter->DeviceConnected(port)) {
  127. std::lock_guard lock{mutex};
  128. const auto axis_value =
  129. static_cast<float>(gcadapter->GetPadState(port).axis_values.at(axis));
  130. return (axis_value) / (100.0f * range);
  131. }
  132. return 0.0f;
  133. }
  134. std::pair<float, float> GetAnalog(u32 analog_axis_x, u32 analog_axis_y) const {
  135. float x = GetAxis(analog_axis_x);
  136. float y = GetAxis(analog_axis_y);
  137. // Make sure the coordinates are in the unit circle,
  138. // otherwise normalize it.
  139. float r = x * x + y * y;
  140. if (r > 1.0f) {
  141. r = std::sqrt(r);
  142. x /= r;
  143. y /= r;
  144. }
  145. return {x, y};
  146. }
  147. std::tuple<float, float> GetStatus() const override {
  148. const auto [x, y] = GetAnalog(axis_x, axis_y);
  149. const float r = std::sqrt((x * x) + (y * y));
  150. if (r > deadzone) {
  151. return {x / r * (r - deadzone) / (1 - deadzone),
  152. y / r * (r - deadzone) / (1 - deadzone)};
  153. }
  154. return {0.0f, 0.0f};
  155. }
  156. bool GetAnalogDirectionStatus(Input::AnalogDirection direction) const override {
  157. const auto [x, y] = GetStatus();
  158. const float directional_deadzone = 0.5f;
  159. switch (direction) {
  160. case Input::AnalogDirection::RIGHT:
  161. return x > directional_deadzone;
  162. case Input::AnalogDirection::LEFT:
  163. return x < -directional_deadzone;
  164. case Input::AnalogDirection::UP:
  165. return y > directional_deadzone;
  166. case Input::AnalogDirection::DOWN:
  167. return y < -directional_deadzone;
  168. }
  169. return false;
  170. }
  171. private:
  172. const u32 port;
  173. const u32 axis_x;
  174. const u32 axis_y;
  175. const float deadzone;
  176. const GCAdapter::Adapter* gcadapter;
  177. const float range;
  178. mutable std::mutex mutex;
  179. };
  180. /// An analog device factory that creates analog devices from GC Adapter
  181. GCAnalogFactory::GCAnalogFactory(std::shared_ptr<GCAdapter::Adapter> adapter_)
  182. : adapter(std::move(adapter_)) {}
  183. /**
  184. * Creates analog device from joystick axes
  185. * @param params contains parameters for creating the device:
  186. * - "port": the nth gcpad on the adapter
  187. * - "axis_x": the index of the axis to be bind as x-axis
  188. * - "axis_y": the index of the axis to be bind as y-axis
  189. */
  190. std::unique_ptr<Input::AnalogDevice> GCAnalogFactory::Create(const Common::ParamPackage& params) {
  191. const auto port = static_cast<u32>(params.Get("port", 0));
  192. const auto axis_x = static_cast<u32>(params.Get("axis_x", 0));
  193. const auto axis_y = static_cast<u32>(params.Get("axis_y", 1));
  194. const auto deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, 1.0f);
  195. const auto range = std::clamp(params.Get("range", 1.0f), 0.50f, 1.50f);
  196. return std::make_unique<GCAnalog>(port, axis_x, axis_y, deadzone, adapter.get(), range);
  197. }
  198. void GCAnalogFactory::BeginConfiguration() {
  199. polling = true;
  200. adapter->BeginConfiguration();
  201. }
  202. void GCAnalogFactory::EndConfiguration() {
  203. polling = false;
  204. adapter->EndConfiguration();
  205. }
  206. Common::ParamPackage GCAnalogFactory::GetNextInput() {
  207. GCAdapter::GCPadStatus pad;
  208. Common::ParamPackage params;
  209. auto& queue = adapter->GetPadQueue();
  210. while (queue.Pop(pad)) {
  211. if (pad.button != GCAdapter::PadButton::Undefined) {
  212. params.Set("engine", "gcpad");
  213. params.Set("port", static_cast<s32>(pad.port));
  214. params.Set("button", static_cast<u16>(pad.button));
  215. return params;
  216. }
  217. if (pad.axis == GCAdapter::PadAxes::Undefined ||
  218. std::abs(static_cast<float>(pad.axis_value) / 128.0f) < 0.1f) {
  219. continue;
  220. }
  221. // An analog device needs two axes, so we need to store the axis for later and wait for
  222. // a second input event. The axes also must be from the same joystick.
  223. const u8 axis = static_cast<u8>(pad.axis);
  224. if (axis == 0 || axis == 1) {
  225. analog_x_axis = 0;
  226. analog_y_axis = 1;
  227. controller_number = static_cast<s32>(pad.port);
  228. break;
  229. }
  230. if (axis == 2 || axis == 3) {
  231. analog_x_axis = 2;
  232. analog_y_axis = 3;
  233. controller_number = static_cast<s32>(pad.port);
  234. break;
  235. }
  236. if (analog_x_axis == -1) {
  237. analog_x_axis = axis;
  238. controller_number = static_cast<s32>(pad.port);
  239. } else if (analog_y_axis == -1 && analog_x_axis != axis &&
  240. controller_number == static_cast<s32>(pad.port)) {
  241. analog_y_axis = axis;
  242. break;
  243. }
  244. }
  245. if (analog_x_axis != -1 && analog_y_axis != -1) {
  246. params.Set("engine", "gcpad");
  247. params.Set("port", controller_number);
  248. params.Set("axis_x", analog_x_axis);
  249. params.Set("axis_y", analog_y_axis);
  250. analog_x_axis = -1;
  251. analog_y_axis = -1;
  252. controller_number = -1;
  253. return params;
  254. }
  255. return params;
  256. }
  257. class GCVibration final : public Input::VibrationDevice {
  258. public:
  259. explicit GCVibration(u32 port_, GCAdapter::Adapter* adapter)
  260. : port(port_), gcadapter(adapter) {}
  261. u8 GetStatus() const override {
  262. return gcadapter->RumblePlay(port, 0);
  263. }
  264. bool SetRumblePlay(f32 amp_low, [[maybe_unused]] f32 freq_low, f32 amp_high,
  265. [[maybe_unused]] f32 freq_high) const override {
  266. const auto mean_amplitude = (amp_low + amp_high) * 0.5f;
  267. const auto processed_amplitude =
  268. static_cast<u8>((mean_amplitude + std::pow(mean_amplitude, 0.3f)) * 0.5f * 0x8);
  269. return gcadapter->RumblePlay(port, processed_amplitude);
  270. }
  271. private:
  272. const u32 port;
  273. GCAdapter::Adapter* gcadapter;
  274. };
  275. /// An vibration device factory that creates vibration devices from GC Adapter
  276. GCVibrationFactory::GCVibrationFactory(std::shared_ptr<GCAdapter::Adapter> adapter_)
  277. : adapter(std::move(adapter_)) {}
  278. /**
  279. * Creates a vibration device from a joystick
  280. * @param params contains parameters for creating the device:
  281. * - "port": the nth gcpad on the adapter
  282. */
  283. std::unique_ptr<Input::VibrationDevice> GCVibrationFactory::Create(
  284. const Common::ParamPackage& params) {
  285. const auto port = static_cast<u32>(params.Get("port", 0));
  286. return std::make_unique<GCVibration>(port, adapter.get());
  287. }
  288. } // namespace InputCommon