gc_poller.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  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_, bool invert_x_, bool invert_y_,
  122. float deadzone_, float range_, const GCAdapter::Adapter* adapter)
  123. : port(port_), axis_x(axis_x_), axis_y(axis_y_), invert_x(invert_x_), invert_y(invert_y_),
  124. deadzone(deadzone_), range(range_), gcadapter(adapter) {}
  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. if (invert_x) {
  138. x = -x;
  139. }
  140. if (invert_y) {
  141. y = -y;
  142. }
  143. // Make sure the coordinates are in the unit circle,
  144. // otherwise normalize it.
  145. float r = x * x + y * y;
  146. if (r > 1.0f) {
  147. r = std::sqrt(r);
  148. x /= r;
  149. y /= r;
  150. }
  151. return {x, y};
  152. }
  153. std::tuple<float, float> GetStatus() const override {
  154. const auto [x, y] = GetAnalog(axis_x, axis_y);
  155. const float r = std::sqrt((x * x) + (y * y));
  156. if (r > deadzone) {
  157. return {x / r * (r - deadzone) / (1 - deadzone),
  158. y / r * (r - deadzone) / (1 - deadzone)};
  159. }
  160. return {0.0f, 0.0f};
  161. }
  162. std::tuple<float, float> GetRawStatus() const override {
  163. const float x = GetAxis(axis_x);
  164. const float y = GetAxis(axis_y);
  165. return {x, y};
  166. }
  167. Input::AnalogProperties GetAnalogProperties() const override {
  168. return {deadzone, range, 0.5f};
  169. }
  170. bool GetAnalogDirectionStatus(Input::AnalogDirection direction) const override {
  171. const auto [x, y] = GetStatus();
  172. const float directional_deadzone = 0.5f;
  173. switch (direction) {
  174. case Input::AnalogDirection::RIGHT:
  175. return x > directional_deadzone;
  176. case Input::AnalogDirection::LEFT:
  177. return x < -directional_deadzone;
  178. case Input::AnalogDirection::UP:
  179. return y > directional_deadzone;
  180. case Input::AnalogDirection::DOWN:
  181. return y < -directional_deadzone;
  182. }
  183. return false;
  184. }
  185. private:
  186. const u32 port;
  187. const u32 axis_x;
  188. const u32 axis_y;
  189. const bool invert_x;
  190. const bool invert_y;
  191. const float deadzone;
  192. const float range;
  193. const GCAdapter::Adapter* gcadapter;
  194. mutable std::mutex mutex;
  195. };
  196. /// An analog device factory that creates analog devices from GC Adapter
  197. GCAnalogFactory::GCAnalogFactory(std::shared_ptr<GCAdapter::Adapter> adapter_)
  198. : adapter(std::move(adapter_)) {}
  199. /**
  200. * Creates analog device from joystick axes
  201. * @param params contains parameters for creating the device:
  202. * - "port": the nth gcpad on the adapter
  203. * - "axis_x": the index of the axis to be bind as x-axis
  204. * - "axis_y": the index of the axis to be bind as y-axis
  205. */
  206. std::unique_ptr<Input::AnalogDevice> GCAnalogFactory::Create(const Common::ParamPackage& params) {
  207. const auto port = static_cast<u32>(params.Get("port", 0));
  208. const auto axis_x = static_cast<u32>(params.Get("axis_x", 0));
  209. const auto axis_y = static_cast<u32>(params.Get("axis_y", 1));
  210. const auto deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, 1.0f);
  211. const auto range = std::clamp(params.Get("range", 1.0f), 0.50f, 1.50f);
  212. const std::string invert_x_value = params.Get("invert_x", "+");
  213. const std::string invert_y_value = params.Get("invert_y", "+");
  214. const bool invert_x = invert_x_value == "-";
  215. const bool invert_y = invert_y_value == "-";
  216. return std::make_unique<GCAnalog>(port, axis_x, axis_y, invert_x, invert_y, deadzone, range,
  217. adapter.get());
  218. }
  219. void GCAnalogFactory::BeginConfiguration() {
  220. polling = true;
  221. adapter->BeginConfiguration();
  222. }
  223. void GCAnalogFactory::EndConfiguration() {
  224. polling = false;
  225. adapter->EndConfiguration();
  226. }
  227. Common::ParamPackage GCAnalogFactory::GetNextInput() {
  228. GCAdapter::GCPadStatus pad;
  229. Common::ParamPackage params;
  230. auto& queue = adapter->GetPadQueue();
  231. while (queue.Pop(pad)) {
  232. if (pad.button != GCAdapter::PadButton::Undefined) {
  233. params.Set("engine", "gcpad");
  234. params.Set("port", static_cast<s32>(pad.port));
  235. params.Set("button", static_cast<u16>(pad.button));
  236. return params;
  237. }
  238. if (pad.axis == GCAdapter::PadAxes::Undefined ||
  239. std::abs(static_cast<float>(pad.axis_value) / 128.0f) < 0.1f) {
  240. continue;
  241. }
  242. // An analog device needs two axes, so we need to store the axis for later and wait for
  243. // a second input event. The axes also must be from the same joystick.
  244. const u8 axis = static_cast<u8>(pad.axis);
  245. if (axis == 0 || axis == 1) {
  246. analog_x_axis = 0;
  247. analog_y_axis = 1;
  248. controller_number = static_cast<s32>(pad.port);
  249. break;
  250. }
  251. if (axis == 2 || axis == 3) {
  252. analog_x_axis = 2;
  253. analog_y_axis = 3;
  254. controller_number = static_cast<s32>(pad.port);
  255. break;
  256. }
  257. if (analog_x_axis == -1) {
  258. analog_x_axis = axis;
  259. controller_number = static_cast<s32>(pad.port);
  260. } else if (analog_y_axis == -1 && analog_x_axis != axis &&
  261. controller_number == static_cast<s32>(pad.port)) {
  262. analog_y_axis = axis;
  263. break;
  264. }
  265. }
  266. if (analog_x_axis != -1 && analog_y_axis != -1) {
  267. params.Set("engine", "gcpad");
  268. params.Set("port", controller_number);
  269. params.Set("axis_x", analog_x_axis);
  270. params.Set("axis_y", analog_y_axis);
  271. params.Set("invert_x", "+");
  272. params.Set("invert_y", "+");
  273. analog_x_axis = -1;
  274. analog_y_axis = -1;
  275. controller_number = -1;
  276. return params;
  277. }
  278. return params;
  279. }
  280. class GCVibration final : public Input::VibrationDevice {
  281. public:
  282. explicit GCVibration(u32 port_, GCAdapter::Adapter* adapter)
  283. : port(port_), gcadapter(adapter) {}
  284. u8 GetStatus() const override {
  285. return gcadapter->RumblePlay(port, 0);
  286. }
  287. bool SetRumblePlay(f32 amp_low, [[maybe_unused]] f32 freq_low, f32 amp_high,
  288. [[maybe_unused]] f32 freq_high) const override {
  289. const auto mean_amplitude = (amp_low + amp_high) * 0.5f;
  290. const auto processed_amplitude =
  291. static_cast<u8>((mean_amplitude + std::pow(mean_amplitude, 0.3f)) * 0.5f * 0x8);
  292. return gcadapter->RumblePlay(port, processed_amplitude);
  293. }
  294. private:
  295. const u32 port;
  296. GCAdapter::Adapter* gcadapter;
  297. };
  298. /// An vibration device factory that creates vibration devices from GC Adapter
  299. GCVibrationFactory::GCVibrationFactory(std::shared_ptr<GCAdapter::Adapter> adapter_)
  300. : adapter(std::move(adapter_)) {}
  301. /**
  302. * Creates a vibration device from a joystick
  303. * @param params contains parameters for creating the device:
  304. * - "port": the nth gcpad on the adapter
  305. */
  306. std::unique_ptr<Input::VibrationDevice> GCVibrationFactory::Create(
  307. const Common::ParamPackage& params) {
  308. const auto port = static_cast<u32>(params.Get("port", 0));
  309. return std::make_unique<GCVibration>(port, adapter.get());
  310. }
  311. } // namespace InputCommon