mouse.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include <thread>
  4. #include <fmt/format.h>
  5. #include <math.h>
  6. #include "common/param_package.h"
  7. #include "common/settings.h"
  8. #include "common/thread.h"
  9. #include "input_common/drivers/mouse.h"
  10. namespace InputCommon {
  11. constexpr int update_time = 10;
  12. constexpr float default_panning_sensitivity = 0.0010f;
  13. constexpr float default_stick_sensitivity = 0.0006f;
  14. constexpr float default_deadzone_counterweight = 0.01f;
  15. constexpr float default_motion_panning_sensitivity = 2.5f;
  16. constexpr float default_motion_sensitivity = 0.416f;
  17. constexpr float maximum_rotation_speed = 2.0f;
  18. constexpr float maximum_stick_range = 1.5f;
  19. constexpr int mouse_axis_x = 0;
  20. constexpr int mouse_axis_y = 1;
  21. constexpr int wheel_axis_x = 2;
  22. constexpr int wheel_axis_y = 3;
  23. constexpr PadIdentifier identifier = {
  24. .guid = Common::UUID{},
  25. .port = 0,
  26. .pad = 0,
  27. };
  28. constexpr PadIdentifier motion_identifier = {
  29. .guid = Common::UUID{},
  30. .port = 0,
  31. .pad = 1,
  32. };
  33. constexpr PadIdentifier real_mouse_identifier = {
  34. .guid = Common::UUID{},
  35. .port = 1,
  36. .pad = 0,
  37. };
  38. constexpr PadIdentifier touch_identifier = {
  39. .guid = Common::UUID{},
  40. .port = 2,
  41. .pad = 0,
  42. };
  43. Mouse::Mouse(std::string input_engine_) : InputEngine(std::move(input_engine_)) {
  44. PreSetController(identifier);
  45. PreSetController(real_mouse_identifier);
  46. PreSetController(touch_identifier);
  47. PreSetController(motion_identifier);
  48. // Initialize all mouse axis
  49. PreSetAxis(identifier, mouse_axis_x);
  50. PreSetAxis(identifier, mouse_axis_y);
  51. PreSetAxis(identifier, wheel_axis_x);
  52. PreSetAxis(identifier, wheel_axis_y);
  53. PreSetAxis(real_mouse_identifier, mouse_axis_x);
  54. PreSetAxis(real_mouse_identifier, mouse_axis_y);
  55. PreSetAxis(touch_identifier, mouse_axis_x);
  56. PreSetAxis(touch_identifier, mouse_axis_y);
  57. // Initialize variables
  58. mouse_origin = {};
  59. last_mouse_position = {};
  60. wheel_position = {};
  61. last_mouse_change = {};
  62. last_motion_change = {};
  63. update_thread = std::jthread([this](std::stop_token stop_token) { UpdateThread(stop_token); });
  64. }
  65. void Mouse::UpdateThread(std::stop_token stop_token) {
  66. Common::SetCurrentThreadName("Mouse");
  67. while (!stop_token.stop_requested()) {
  68. UpdateStickInput();
  69. UpdateMotionInput();
  70. std::this_thread::sleep_for(std::chrono::milliseconds(update_time));
  71. }
  72. }
  73. void Mouse::UpdateStickInput() {
  74. if (!Settings::values.mouse_panning) {
  75. return;
  76. }
  77. const float length = last_mouse_change.Length();
  78. // Prevent input from exceeding the max range (1.0f) too much,
  79. // but allow some room to make it easier to sustain
  80. if (length > maximum_stick_range) {
  81. last_mouse_change /= length;
  82. last_mouse_change *= maximum_stick_range;
  83. }
  84. SetAxis(identifier, mouse_axis_x, last_mouse_change.x);
  85. SetAxis(identifier, mouse_axis_y, -last_mouse_change.y);
  86. // Decay input over time
  87. const float clamped_length = std::min(1.0f, length);
  88. const float decay_strength = Settings::values.mouse_panning_decay_strength.GetValue();
  89. const float decay = 1 - clamped_length * clamped_length * decay_strength * 0.01f;
  90. const float min_decay = Settings::values.mouse_panning_min_decay.GetValue();
  91. const float clamped_decay = std::min(1 - min_decay / 100.0f, decay);
  92. last_mouse_change *= clamped_decay;
  93. }
  94. void Mouse::UpdateMotionInput() {
  95. const float sensitivity = Settings::values.mouse_panning ? default_motion_panning_sensitivity
  96. : default_motion_sensitivity;
  97. const float rotation_velocity = std::sqrt(last_motion_change.x * last_motion_change.x +
  98. last_motion_change.y * last_motion_change.y);
  99. // Clamp rotation speed
  100. if (rotation_velocity > maximum_rotation_speed / sensitivity) {
  101. const float multiplier = maximum_rotation_speed / rotation_velocity / sensitivity;
  102. last_motion_change.x = last_motion_change.x * multiplier;
  103. last_motion_change.y = last_motion_change.y * multiplier;
  104. }
  105. const BasicMotion motion_data{
  106. .gyro_x = last_motion_change.x * sensitivity,
  107. .gyro_y = last_motion_change.y * sensitivity,
  108. .gyro_z = last_motion_change.z * sensitivity,
  109. .accel_x = 0,
  110. .accel_y = 0,
  111. .accel_z = 0,
  112. .delta_timestamp = update_time * 1000,
  113. };
  114. if (Settings::values.mouse_panning) {
  115. last_motion_change.x = 0;
  116. last_motion_change.y = 0;
  117. }
  118. last_motion_change.z = 0;
  119. SetMotion(motion_identifier, 0, motion_data);
  120. }
  121. void Mouse::Move(int x, int y, int center_x, int center_y) {
  122. if (Settings::values.mouse_panning) {
  123. const auto mouse_change =
  124. (Common::MakeVec(x, y) - Common::MakeVec(center_x, center_y)).Cast<float>();
  125. const float x_sensitivity =
  126. Settings::values.mouse_panning_x_sensitivity.GetValue() * default_panning_sensitivity;
  127. const float y_sensitivity =
  128. Settings::values.mouse_panning_y_sensitivity.GetValue() * default_panning_sensitivity;
  129. const float deadzone_counterweight =
  130. Settings::values.mouse_panning_deadzone_counterweight.GetValue() *
  131. default_deadzone_counterweight;
  132. last_motion_change += {-mouse_change.y * x_sensitivity, -mouse_change.x * y_sensitivity, 0};
  133. last_mouse_change.x += mouse_change.x * x_sensitivity;
  134. last_mouse_change.y += mouse_change.y * y_sensitivity;
  135. // Bind the mouse change to [0 <= deadzone_counterweight <= 1.0]
  136. if (last_mouse_change.Length() < deadzone_counterweight) {
  137. last_mouse_change /= last_mouse_change.Length();
  138. last_mouse_change *= deadzone_counterweight;
  139. }
  140. return;
  141. }
  142. if (button_pressed) {
  143. const auto mouse_move = Common::MakeVec<int>(x, y) - mouse_origin;
  144. const float x_sensitivity =
  145. Settings::values.mouse_panning_x_sensitivity.GetValue() * default_stick_sensitivity;
  146. const float y_sensitivity =
  147. Settings::values.mouse_panning_y_sensitivity.GetValue() * default_stick_sensitivity;
  148. SetAxis(identifier, mouse_axis_x, static_cast<float>(mouse_move.x) * x_sensitivity);
  149. SetAxis(identifier, mouse_axis_y, static_cast<float>(-mouse_move.y) * y_sensitivity);
  150. last_motion_change = {
  151. static_cast<float>(-mouse_move.y) * x_sensitivity,
  152. static_cast<float>(-mouse_move.x) * y_sensitivity,
  153. last_motion_change.z,
  154. };
  155. }
  156. }
  157. void Mouse::MouseMove(f32 touch_x, f32 touch_y) {
  158. SetAxis(real_mouse_identifier, mouse_axis_x, touch_x);
  159. SetAxis(real_mouse_identifier, mouse_axis_y, touch_y);
  160. }
  161. void Mouse::TouchMove(f32 touch_x, f32 touch_y) {
  162. SetAxis(touch_identifier, mouse_axis_x, touch_x);
  163. SetAxis(touch_identifier, mouse_axis_y, touch_y);
  164. }
  165. void Mouse::PressButton(int x, int y, MouseButton button) {
  166. SetButton(identifier, static_cast<int>(button), true);
  167. // Set initial analog parameters
  168. mouse_origin = {x, y};
  169. last_mouse_position = {x, y};
  170. button_pressed = true;
  171. }
  172. void Mouse::PressMouseButton(MouseButton button) {
  173. SetButton(real_mouse_identifier, static_cast<int>(button), true);
  174. }
  175. void Mouse::PressTouchButton(f32 touch_x, f32 touch_y, MouseButton button) {
  176. SetAxis(touch_identifier, mouse_axis_x, touch_x);
  177. SetAxis(touch_identifier, mouse_axis_y, touch_y);
  178. SetButton(touch_identifier, static_cast<int>(button), true);
  179. }
  180. void Mouse::ReleaseButton(MouseButton button) {
  181. SetButton(identifier, static_cast<int>(button), false);
  182. SetButton(real_mouse_identifier, static_cast<int>(button), false);
  183. SetButton(touch_identifier, static_cast<int>(button), false);
  184. if (!Settings::values.mouse_panning) {
  185. SetAxis(identifier, mouse_axis_x, 0);
  186. SetAxis(identifier, mouse_axis_y, 0);
  187. }
  188. last_motion_change.x = 0;
  189. last_motion_change.y = 0;
  190. button_pressed = false;
  191. }
  192. void Mouse::MouseWheelChange(int x, int y) {
  193. wheel_position.x += x;
  194. wheel_position.y += y;
  195. last_motion_change.z += static_cast<f32>(y);
  196. SetAxis(identifier, wheel_axis_x, static_cast<f32>(wheel_position.x));
  197. SetAxis(identifier, wheel_axis_y, static_cast<f32>(wheel_position.y));
  198. }
  199. void Mouse::ReleaseAllButtons() {
  200. ResetButtonState();
  201. button_pressed = false;
  202. }
  203. std::vector<Common::ParamPackage> Mouse::GetInputDevices() const {
  204. std::vector<Common::ParamPackage> devices;
  205. devices.emplace_back(Common::ParamPackage{
  206. {"engine", GetEngineName()},
  207. {"display", "Keyboard/Mouse"},
  208. });
  209. return devices;
  210. }
  211. AnalogMapping Mouse::GetAnalogMappingForDevice(
  212. [[maybe_unused]] const Common::ParamPackage& params) {
  213. // Only overwrite different buttons from default
  214. AnalogMapping mapping = {};
  215. Common::ParamPackage right_analog_params;
  216. right_analog_params.Set("engine", GetEngineName());
  217. right_analog_params.Set("axis_x", 0);
  218. right_analog_params.Set("axis_y", 1);
  219. right_analog_params.Set("threshold", 0.5f);
  220. right_analog_params.Set("range", 1.0f);
  221. right_analog_params.Set("deadzone", 0.0f);
  222. mapping.insert_or_assign(Settings::NativeAnalog::RStick, std::move(right_analog_params));
  223. return mapping;
  224. }
  225. Common::Input::ButtonNames Mouse::GetUIButtonName(const Common::ParamPackage& params) const {
  226. const auto button = static_cast<MouseButton>(params.Get("button", 0));
  227. switch (button) {
  228. case MouseButton::Left:
  229. return Common::Input::ButtonNames::ButtonLeft;
  230. case MouseButton::Right:
  231. return Common::Input::ButtonNames::ButtonRight;
  232. case MouseButton::Wheel:
  233. return Common::Input::ButtonNames::ButtonMouseWheel;
  234. case MouseButton::Backward:
  235. return Common::Input::ButtonNames::ButtonBackward;
  236. case MouseButton::Forward:
  237. return Common::Input::ButtonNames::ButtonForward;
  238. case MouseButton::Task:
  239. return Common::Input::ButtonNames::ButtonTask;
  240. case MouseButton::Extra:
  241. return Common::Input::ButtonNames::ButtonExtra;
  242. case MouseButton::Undefined:
  243. default:
  244. return Common::Input::ButtonNames::Undefined;
  245. }
  246. }
  247. Common::Input::ButtonNames Mouse::GetUIName(const Common::ParamPackage& params) const {
  248. if (params.Has("button")) {
  249. return GetUIButtonName(params);
  250. }
  251. if (params.Has("axis")) {
  252. return Common::Input::ButtonNames::Value;
  253. }
  254. if (params.Has("axis_x") && params.Has("axis_y") && params.Has("axis_z")) {
  255. return Common::Input::ButtonNames::Engine;
  256. }
  257. if (params.Has("motion")) {
  258. return Common::Input::ButtonNames::Engine;
  259. }
  260. return Common::Input::ButtonNames::Invalid;
  261. }
  262. } // namespace InputCommon