emulated_console.cpp 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include "common/settings.h"
  4. #include "core/hid/emulated_console.h"
  5. #include "core/hid/input_converter.h"
  6. namespace Core::HID {
  7. EmulatedConsole::EmulatedConsole() = default;
  8. EmulatedConsole::~EmulatedConsole() = default;
  9. void EmulatedConsole::ReloadFromSettings() {
  10. // Using first motion device from player 1. No need to assign any unique config at the moment
  11. const auto& player = Settings::values.players.GetValue()[0];
  12. motion_params = Common::ParamPackage(player.motions[0]);
  13. ReloadInput();
  14. }
  15. void EmulatedConsole::SetTouchParams() {
  16. std::size_t index = 0;
  17. // We can't use mouse as touch if native mouse is enabled
  18. if (!Settings::values.mouse_enabled) {
  19. touch_params[index++] = Common::ParamPackage{"engine:mouse,axis_x:10,axis_y:11,button:0"};
  20. }
  21. touch_params[index++] =
  22. Common::ParamPackage{"engine:cemuhookudp,axis_x:17,axis_y:18,button:65536"};
  23. touch_params[index++] =
  24. Common::ParamPackage{"engine:cemuhookudp,axis_x:19,axis_y:20,button:131072"};
  25. for (int i = 0; i < static_cast<int>(MaxActiveTouchInputs); i++) {
  26. Common::ParamPackage touchscreen_param{};
  27. touchscreen_param.Set("engine", "touch");
  28. touchscreen_param.Set("axis_x", i * 2);
  29. touchscreen_param.Set("axis_y", (i * 2) + 1);
  30. touchscreen_param.Set("button", i);
  31. touch_params[index++] = touchscreen_param;
  32. }
  33. const auto button_index =
  34. static_cast<u64>(Settings::values.touch_from_button_map_index.GetValue());
  35. const auto& touch_buttons = Settings::values.touch_from_button_maps[button_index].buttons;
  36. // Map the rest of the fingers from touch from button configuration
  37. for (const auto& config_entry : touch_buttons) {
  38. if (index >= MaxTouchDevices) {
  39. continue;
  40. }
  41. Common::ParamPackage params{config_entry};
  42. Common::ParamPackage touch_button_params;
  43. const int x = params.Get("x", 0);
  44. const int y = params.Get("y", 0);
  45. params.Erase("x");
  46. params.Erase("y");
  47. touch_button_params.Set("engine", "touch_from_button");
  48. touch_button_params.Set("button", params.Serialize());
  49. touch_button_params.Set("x", x);
  50. touch_button_params.Set("y", y);
  51. touch_params[index] = touch_button_params;
  52. index++;
  53. }
  54. }
  55. void EmulatedConsole::ReloadInput() {
  56. // If you load any device here add the equivalent to the UnloadInput() function
  57. SetTouchParams();
  58. motion_devices = Common::Input::CreateDevice<Common::Input::InputDevice>(motion_params);
  59. if (motion_devices) {
  60. motion_devices->SetCallback({
  61. .on_change =
  62. [this](const Common::Input::CallbackStatus& callback) { SetMotion(callback); },
  63. });
  64. }
  65. // Unique index for identifying touch device source
  66. std::size_t index = 0;
  67. for (auto& touch_device : touch_devices) {
  68. touch_device = Common::Input::CreateDevice<Common::Input::InputDevice>(touch_params[index]);
  69. if (!touch_device) {
  70. continue;
  71. }
  72. touch_device->SetCallback({
  73. .on_change =
  74. [this, index](const Common::Input::CallbackStatus& callback) {
  75. SetTouch(callback, index);
  76. },
  77. });
  78. index++;
  79. }
  80. }
  81. void EmulatedConsole::UnloadInput() {
  82. motion_devices.reset();
  83. for (auto& touch : touch_devices) {
  84. touch.reset();
  85. }
  86. }
  87. void EmulatedConsole::EnableConfiguration() {
  88. is_configuring = true;
  89. SaveCurrentConfig();
  90. }
  91. void EmulatedConsole::DisableConfiguration() {
  92. is_configuring = false;
  93. }
  94. bool EmulatedConsole::IsConfiguring() const {
  95. return is_configuring;
  96. }
  97. void EmulatedConsole::SaveCurrentConfig() {
  98. if (!is_configuring) {
  99. return;
  100. }
  101. }
  102. void EmulatedConsole::RestoreConfig() {
  103. if (!is_configuring) {
  104. return;
  105. }
  106. ReloadFromSettings();
  107. }
  108. Common::ParamPackage EmulatedConsole::GetMotionParam() const {
  109. return motion_params;
  110. }
  111. void EmulatedConsole::SetMotionParam(Common::ParamPackage param) {
  112. motion_params = param;
  113. ReloadInput();
  114. }
  115. void EmulatedConsole::SetMotion(const Common::Input::CallbackStatus& callback) {
  116. std::unique_lock lock{mutex};
  117. auto& raw_status = console.motion_values.raw_status;
  118. auto& emulated = console.motion_values.emulated;
  119. raw_status = TransformToMotion(callback);
  120. emulated.SetAcceleration(Common::Vec3f{
  121. raw_status.accel.x.value,
  122. raw_status.accel.y.value,
  123. raw_status.accel.z.value,
  124. });
  125. emulated.SetGyroscope(Common::Vec3f{
  126. raw_status.gyro.x.value,
  127. raw_status.gyro.y.value,
  128. raw_status.gyro.z.value,
  129. });
  130. emulated.UpdateRotation(raw_status.delta_timestamp);
  131. emulated.UpdateOrientation(raw_status.delta_timestamp);
  132. if (is_configuring) {
  133. lock.unlock();
  134. TriggerOnChange(ConsoleTriggerType::Motion);
  135. return;
  136. }
  137. auto& motion = console.motion_state;
  138. motion.accel = emulated.GetAcceleration();
  139. motion.gyro = emulated.GetGyroscope();
  140. motion.rotation = emulated.GetRotations();
  141. motion.orientation = emulated.GetOrientation();
  142. motion.quaternion = emulated.GetQuaternion();
  143. motion.gyro_bias = emulated.GetGyroBias();
  144. motion.is_at_rest = !emulated.IsMoving(motion_sensitivity);
  145. // Find what is this value
  146. motion.verticalization_error = 0.0f;
  147. lock.unlock();
  148. TriggerOnChange(ConsoleTriggerType::Motion);
  149. }
  150. void EmulatedConsole::SetTouch(const Common::Input::CallbackStatus& callback, std::size_t index) {
  151. if (index >= MaxTouchDevices) {
  152. return;
  153. }
  154. std::unique_lock lock{mutex};
  155. const auto touch_input = TransformToTouch(callback);
  156. auto touch_index = GetIndexFromFingerId(index);
  157. bool is_new_input = false;
  158. if (!touch_index.has_value() && touch_input.pressed.value) {
  159. touch_index = GetNextFreeIndex();
  160. is_new_input = true;
  161. }
  162. // No free entries or invalid state. Ignore input
  163. if (!touch_index.has_value()) {
  164. return;
  165. }
  166. auto& touch_value = console.touch_values[touch_index.value()];
  167. if (is_new_input) {
  168. touch_value.pressed.value = true;
  169. touch_value.id = static_cast<u32>(index);
  170. }
  171. touch_value.x = touch_input.x;
  172. touch_value.y = touch_input.y;
  173. if (!touch_input.pressed.value) {
  174. touch_value.pressed.value = false;
  175. }
  176. if (is_configuring) {
  177. lock.unlock();
  178. TriggerOnChange(ConsoleTriggerType::Touch);
  179. return;
  180. }
  181. // Touch outside allowed range. Ignore input
  182. if (touch_index.value() >= MaxActiveTouchInputs) {
  183. return;
  184. }
  185. console.touch_state[touch_index.value()] = {
  186. .position = {touch_value.x.value, touch_value.y.value},
  187. .id = static_cast<u32>(touch_index.value()),
  188. .pressed = touch_input.pressed.value,
  189. };
  190. lock.unlock();
  191. TriggerOnChange(ConsoleTriggerType::Touch);
  192. }
  193. ConsoleMotionValues EmulatedConsole::GetMotionValues() const {
  194. std::scoped_lock lock{mutex};
  195. return console.motion_values;
  196. }
  197. TouchValues EmulatedConsole::GetTouchValues() const {
  198. std::scoped_lock lock{mutex};
  199. return console.touch_values;
  200. }
  201. ConsoleMotion EmulatedConsole::GetMotion() const {
  202. std::scoped_lock lock{mutex};
  203. return console.motion_state;
  204. }
  205. TouchFingerState EmulatedConsole::GetTouch() const {
  206. std::scoped_lock lock{mutex};
  207. return console.touch_state;
  208. }
  209. std::optional<std::size_t> EmulatedConsole::GetIndexFromFingerId(std::size_t finger_id) const {
  210. for (std::size_t index = 0; index < MaxTouchDevices; ++index) {
  211. const auto& finger = console.touch_values[index];
  212. if (!finger.pressed.value) {
  213. continue;
  214. }
  215. if (finger.id == static_cast<int>(finger_id)) {
  216. return index;
  217. }
  218. }
  219. return std::nullopt;
  220. }
  221. std::optional<std::size_t> EmulatedConsole::GetNextFreeIndex() const {
  222. for (std::size_t index = 0; index < MaxTouchDevices; ++index) {
  223. if (!console.touch_values[index].pressed.value) {
  224. return index;
  225. }
  226. }
  227. return std::nullopt;
  228. }
  229. void EmulatedConsole::TriggerOnChange(ConsoleTriggerType type) {
  230. std::scoped_lock lock{callback_mutex};
  231. for (const auto& poller_pair : callback_list) {
  232. const ConsoleUpdateCallback& poller = poller_pair.second;
  233. if (poller.on_change) {
  234. poller.on_change(type);
  235. }
  236. }
  237. }
  238. int EmulatedConsole::SetCallback(ConsoleUpdateCallback update_callback) {
  239. std::scoped_lock lock{callback_mutex};
  240. callback_list.insert_or_assign(last_callback_key, update_callback);
  241. return last_callback_key++;
  242. }
  243. void EmulatedConsole::DeleteCallback(int key) {
  244. std::scoped_lock lock{callback_mutex};
  245. const auto& iterator = callback_list.find(key);
  246. if (iterator == callback_list.end()) {
  247. LOG_ERROR(Input, "Tried to delete non-existent callback {}", key);
  248. return;
  249. }
  250. callback_list.erase(iterator);
  251. }
  252. } // namespace Core::HID