mouse_poller.cpp 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. // Copyright 2020 yuzu Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <algorithm>
  5. #include <memory>
  6. #include <mutex>
  7. #include <utility>
  8. #include "common/settings.h"
  9. #include "common/threadsafe_queue.h"
  10. #include "input_common/mouse/mouse_input.h"
  11. #include "input_common/mouse/mouse_poller.h"
  12. namespace InputCommon {
  13. class MouseButton final : public Input::ButtonDevice {
  14. public:
  15. explicit MouseButton(u32 button_, bool toggle_, MouseInput::Mouse* mouse_input_)
  16. : button(button_), toggle(toggle_), mouse_input(mouse_input_) {}
  17. bool GetStatus() const override {
  18. const bool button_state = mouse_input->GetMouseState(button).pressed;
  19. if (!toggle) {
  20. return button_state;
  21. }
  22. if (button_state) {
  23. return mouse_input->ToggleButton(button);
  24. }
  25. return mouse_input->UnlockButton(button);
  26. }
  27. private:
  28. const u32 button;
  29. const bool toggle;
  30. MouseInput::Mouse* mouse_input;
  31. };
  32. MouseButtonFactory::MouseButtonFactory(std::shared_ptr<MouseInput::Mouse> mouse_input_)
  33. : mouse_input(std::move(mouse_input_)) {}
  34. std::unique_ptr<Input::ButtonDevice> MouseButtonFactory::Create(
  35. const Common::ParamPackage& params) {
  36. const auto button_id = params.Get("button", 0);
  37. const auto toggle = params.Get("toggle", false);
  38. return std::make_unique<MouseButton>(button_id, toggle, mouse_input.get());
  39. }
  40. Common::ParamPackage MouseButtonFactory::GetNextInput() const {
  41. MouseInput::MouseStatus pad;
  42. Common::ParamPackage params;
  43. auto& queue = mouse_input->GetMouseQueue();
  44. while (queue.Pop(pad)) {
  45. // This while loop will break on the earliest detected button
  46. if (pad.button != MouseInput::MouseButton::Undefined) {
  47. params.Set("engine", "mouse");
  48. params.Set("button", static_cast<u16>(pad.button));
  49. return params;
  50. }
  51. }
  52. return params;
  53. }
  54. void MouseButtonFactory::BeginConfiguration() {
  55. polling = true;
  56. mouse_input->BeginConfiguration();
  57. }
  58. void MouseButtonFactory::EndConfiguration() {
  59. polling = false;
  60. mouse_input->EndConfiguration();
  61. }
  62. class MouseAnalog final : public Input::AnalogDevice {
  63. public:
  64. explicit MouseAnalog(u32 port_, u32 axis_x_, u32 axis_y_, bool invert_x_, bool invert_y_,
  65. float deadzone_, float range_, const MouseInput::Mouse* mouse_input_)
  66. : button(port_), axis_x(axis_x_), axis_y(axis_y_), invert_x(invert_x_), invert_y(invert_y_),
  67. deadzone(deadzone_), range(range_), mouse_input(mouse_input_) {}
  68. float GetAxis(u32 axis) const {
  69. std::lock_guard lock{mutex};
  70. const auto axis_value =
  71. static_cast<float>(mouse_input->GetMouseState(button).axis.at(axis));
  72. return axis_value * Settings::values.mouse_panning_sensitivity / (100.0f * range);
  73. }
  74. std::pair<float, float> GetAnalog(u32 analog_axis_x, u32 analog_axis_y) const {
  75. float x = GetAxis(analog_axis_x);
  76. float y = GetAxis(analog_axis_y);
  77. if (invert_x) {
  78. x = -x;
  79. }
  80. if (invert_y) {
  81. y = -y;
  82. }
  83. // Make sure the coordinates are in the unit circle,
  84. // otherwise normalize it.
  85. float r = x * x + y * y;
  86. if (r > 1.0f) {
  87. r = std::sqrt(r);
  88. x /= r;
  89. y /= r;
  90. }
  91. return {x, y};
  92. }
  93. std::tuple<float, float> GetStatus() const override {
  94. const auto [x, y] = GetAnalog(axis_x, axis_y);
  95. const float r = std::sqrt((x * x) + (y * y));
  96. if (r > deadzone) {
  97. return {x / r * (r - deadzone) / (1 - deadzone),
  98. y / r * (r - deadzone) / (1 - deadzone)};
  99. }
  100. return {0.0f, 0.0f};
  101. }
  102. std::tuple<float, float> GetRawStatus() const override {
  103. const float x = GetAxis(axis_x);
  104. const float y = GetAxis(axis_y);
  105. return {x, y};
  106. }
  107. Input::AnalogProperties GetAnalogProperties() const override {
  108. return {deadzone, range, 0.5f};
  109. }
  110. private:
  111. const u32 button;
  112. const u32 axis_x;
  113. const u32 axis_y;
  114. const bool invert_x;
  115. const bool invert_y;
  116. const float deadzone;
  117. const float range;
  118. const MouseInput::Mouse* mouse_input;
  119. mutable std::mutex mutex;
  120. };
  121. /// An analog device factory that creates analog devices from GC Adapter
  122. MouseAnalogFactory::MouseAnalogFactory(std::shared_ptr<MouseInput::Mouse> mouse_input_)
  123. : mouse_input(std::move(mouse_input_)) {}
  124. /**
  125. * Creates analog device from joystick axes
  126. * @param params contains parameters for creating the device:
  127. * - "port": the nth gcpad on the adapter
  128. * - "axis_x": the index of the axis to be bind as x-axis
  129. * - "axis_y": the index of the axis to be bind as y-axis
  130. */
  131. std::unique_ptr<Input::AnalogDevice> MouseAnalogFactory::Create(
  132. const Common::ParamPackage& params) {
  133. const auto port = static_cast<u32>(params.Get("port", 0));
  134. const auto axis_x = static_cast<u32>(params.Get("axis_x", 0));
  135. const auto axis_y = static_cast<u32>(params.Get("axis_y", 1));
  136. const auto deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, 1.0f);
  137. const auto range = std::clamp(params.Get("range", 1.0f), 0.50f, 1.50f);
  138. const std::string invert_x_value = params.Get("invert_x", "+");
  139. const std::string invert_y_value = params.Get("invert_y", "+");
  140. const bool invert_x = invert_x_value == "-";
  141. const bool invert_y = invert_y_value == "-";
  142. return std::make_unique<MouseAnalog>(port, axis_x, axis_y, invert_x, invert_y, deadzone, range,
  143. mouse_input.get());
  144. }
  145. void MouseAnalogFactory::BeginConfiguration() {
  146. polling = true;
  147. mouse_input->BeginConfiguration();
  148. }
  149. void MouseAnalogFactory::EndConfiguration() {
  150. polling = false;
  151. mouse_input->EndConfiguration();
  152. }
  153. Common::ParamPackage MouseAnalogFactory::GetNextInput() const {
  154. MouseInput::MouseStatus pad;
  155. Common::ParamPackage params;
  156. auto& queue = mouse_input->GetMouseQueue();
  157. while (queue.Pop(pad)) {
  158. // This while loop will break on the earliest detected button
  159. if (pad.button != MouseInput::MouseButton::Undefined) {
  160. params.Set("engine", "mouse");
  161. params.Set("port", static_cast<u16>(pad.button));
  162. params.Set("axis_x", 0);
  163. params.Set("axis_y", 1);
  164. params.Set("invert_x", "+");
  165. params.Set("invert_y", "+");
  166. return params;
  167. }
  168. }
  169. return params;
  170. }
  171. class MouseMotion final : public Input::MotionDevice {
  172. public:
  173. explicit MouseMotion(u32 button_, const MouseInput::Mouse* mouse_input_)
  174. : button(button_), mouse_input(mouse_input_) {}
  175. Input::MotionStatus GetStatus() const override {
  176. return mouse_input->GetMouseState(button).motion;
  177. }
  178. private:
  179. const u32 button;
  180. const MouseInput::Mouse* mouse_input;
  181. };
  182. MouseMotionFactory::MouseMotionFactory(std::shared_ptr<MouseInput::Mouse> mouse_input_)
  183. : mouse_input(std::move(mouse_input_)) {}
  184. std::unique_ptr<Input::MotionDevice> MouseMotionFactory::Create(
  185. const Common::ParamPackage& params) {
  186. const auto button_id = params.Get("button", 0);
  187. return std::make_unique<MouseMotion>(button_id, mouse_input.get());
  188. }
  189. Common::ParamPackage MouseMotionFactory::GetNextInput() const {
  190. MouseInput::MouseStatus pad;
  191. Common::ParamPackage params;
  192. auto& queue = mouse_input->GetMouseQueue();
  193. while (queue.Pop(pad)) {
  194. // This while loop will break on the earliest detected button
  195. if (pad.button != MouseInput::MouseButton::Undefined) {
  196. params.Set("engine", "mouse");
  197. params.Set("button", static_cast<u16>(pad.button));
  198. return params;
  199. }
  200. }
  201. return params;
  202. }
  203. void MouseMotionFactory::BeginConfiguration() {
  204. polling = true;
  205. mouse_input->BeginConfiguration();
  206. }
  207. void MouseMotionFactory::EndConfiguration() {
  208. polling = false;
  209. mouse_input->EndConfiguration();
  210. }
  211. class MouseTouch final : public Input::TouchDevice {
  212. public:
  213. explicit MouseTouch(u32 button_, const MouseInput::Mouse* mouse_input_)
  214. : button(button_), mouse_input(mouse_input_) {}
  215. Input::TouchStatus GetStatus() const override {
  216. return mouse_input->GetMouseState(button).touch;
  217. }
  218. private:
  219. const u32 button;
  220. const MouseInput::Mouse* mouse_input;
  221. };
  222. MouseTouchFactory::MouseTouchFactory(std::shared_ptr<MouseInput::Mouse> mouse_input_)
  223. : mouse_input(std::move(mouse_input_)) {}
  224. std::unique_ptr<Input::TouchDevice> MouseTouchFactory::Create(const Common::ParamPackage& params) {
  225. const auto button_id = params.Get("button", 0);
  226. return std::make_unique<MouseTouch>(button_id, mouse_input.get());
  227. }
  228. Common::ParamPackage MouseTouchFactory::GetNextInput() const {
  229. MouseInput::MouseStatus pad;
  230. Common::ParamPackage params;
  231. auto& queue = mouse_input->GetMouseQueue();
  232. while (queue.Pop(pad)) {
  233. // This while loop will break on the earliest detected button
  234. if (pad.button != MouseInput::MouseButton::Undefined) {
  235. params.Set("engine", "mouse");
  236. params.Set("button", static_cast<u16>(pad.button));
  237. return params;
  238. }
  239. }
  240. return params;
  241. }
  242. void MouseTouchFactory::BeginConfiguration() {
  243. polling = true;
  244. mouse_input->BeginConfiguration();
  245. }
  246. void MouseTouchFactory::EndConfiguration() {
  247. polling = false;
  248. mouse_input->EndConfiguration();
  249. }
  250. } // namespace InputCommon