emulated_devices.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477
  1. // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include <algorithm>
  4. #include <fmt/format.h>
  5. #include "core/hid/emulated_devices.h"
  6. #include "core/hid/input_converter.h"
  7. namespace Core::HID {
  8. EmulatedDevices::EmulatedDevices() = default;
  9. EmulatedDevices::~EmulatedDevices() = default;
  10. void EmulatedDevices::ReloadFromSettings() {
  11. ReloadInput();
  12. }
  13. void EmulatedDevices::ReloadInput() {
  14. // If you load any device here add the equivalent to the UnloadInput() function
  15. std::size_t key_index = 0;
  16. for (auto& mouse_device : mouse_button_devices) {
  17. Common::ParamPackage mouse_params;
  18. mouse_params.Set("engine", "mouse");
  19. mouse_params.Set("button", static_cast<int>(key_index));
  20. mouse_device = Common::Input::CreateInputDevice(mouse_params);
  21. key_index++;
  22. }
  23. mouse_stick_device =
  24. Common::Input::CreateInputDeviceFromString("engine:mouse,axis_x:0,axis_y:1");
  25. // First two axis are reserved for mouse position
  26. key_index = 2;
  27. for (auto& mouse_device : mouse_analog_devices) {
  28. Common::ParamPackage mouse_params;
  29. mouse_params.Set("engine", "mouse");
  30. mouse_params.Set("axis", static_cast<int>(key_index));
  31. mouse_device = Common::Input::CreateInputDevice(mouse_params);
  32. key_index++;
  33. }
  34. key_index = 0;
  35. for (auto& keyboard_device : keyboard_devices) {
  36. // Keyboard keys are only mapped on port 1, pad 0
  37. Common::ParamPackage keyboard_params;
  38. keyboard_params.Set("engine", "keyboard");
  39. keyboard_params.Set("button", static_cast<int>(key_index));
  40. keyboard_params.Set("port", 1);
  41. keyboard_params.Set("pad", 0);
  42. keyboard_device = Common::Input::CreateInputDevice(keyboard_params);
  43. key_index++;
  44. }
  45. key_index = 0;
  46. for (auto& keyboard_device : keyboard_modifier_devices) {
  47. // Keyboard moddifiers are only mapped on port 1, pad 1
  48. Common::ParamPackage keyboard_params;
  49. keyboard_params.Set("engine", "keyboard");
  50. keyboard_params.Set("button", static_cast<int>(key_index));
  51. keyboard_params.Set("port", 1);
  52. keyboard_params.Set("pad", 1);
  53. keyboard_device = Common::Input::CreateInputDevice(keyboard_params);
  54. key_index++;
  55. }
  56. for (std::size_t index = 0; index < mouse_button_devices.size(); ++index) {
  57. if (!mouse_button_devices[index]) {
  58. continue;
  59. }
  60. mouse_button_devices[index]->SetCallback({
  61. .on_change =
  62. [this, index](const Common::Input::CallbackStatus& callback) {
  63. SetMouseButton(callback, index);
  64. },
  65. });
  66. }
  67. for (std::size_t index = 0; index < mouse_analog_devices.size(); ++index) {
  68. if (!mouse_analog_devices[index]) {
  69. continue;
  70. }
  71. mouse_analog_devices[index]->SetCallback({
  72. .on_change =
  73. [this, index](const Common::Input::CallbackStatus& callback) {
  74. SetMouseAnalog(callback, index);
  75. },
  76. });
  77. }
  78. if (mouse_stick_device) {
  79. mouse_stick_device->SetCallback({
  80. .on_change =
  81. [this](const Common::Input::CallbackStatus& callback) { SetMouseStick(callback); },
  82. });
  83. }
  84. for (std::size_t index = 0; index < keyboard_devices.size(); ++index) {
  85. if (!keyboard_devices[index]) {
  86. continue;
  87. }
  88. keyboard_devices[index]->SetCallback({
  89. .on_change =
  90. [this, index](const Common::Input::CallbackStatus& callback) {
  91. SetKeyboardButton(callback, index);
  92. },
  93. });
  94. }
  95. for (std::size_t index = 0; index < keyboard_modifier_devices.size(); ++index) {
  96. if (!keyboard_modifier_devices[index]) {
  97. continue;
  98. }
  99. keyboard_modifier_devices[index]->SetCallback({
  100. .on_change =
  101. [this, index](const Common::Input::CallbackStatus& callback) {
  102. SetKeyboardModifier(callback, index);
  103. },
  104. });
  105. }
  106. }
  107. void EmulatedDevices::UnloadInput() {
  108. for (auto& button : mouse_button_devices) {
  109. button.reset();
  110. }
  111. for (auto& analog : mouse_analog_devices) {
  112. analog.reset();
  113. }
  114. mouse_stick_device.reset();
  115. for (auto& button : keyboard_devices) {
  116. button.reset();
  117. }
  118. for (auto& button : keyboard_modifier_devices) {
  119. button.reset();
  120. }
  121. }
  122. void EmulatedDevices::EnableConfiguration() {
  123. is_configuring = true;
  124. SaveCurrentConfig();
  125. }
  126. void EmulatedDevices::DisableConfiguration() {
  127. is_configuring = false;
  128. }
  129. bool EmulatedDevices::IsConfiguring() const {
  130. return is_configuring;
  131. }
  132. void EmulatedDevices::SaveCurrentConfig() {
  133. if (!is_configuring) {
  134. return;
  135. }
  136. }
  137. void EmulatedDevices::RestoreConfig() {
  138. if (!is_configuring) {
  139. return;
  140. }
  141. ReloadFromSettings();
  142. }
  143. void EmulatedDevices::SetKeyboardButton(const Common::Input::CallbackStatus& callback,
  144. std::size_t index) {
  145. if (index >= device_status.keyboard_values.size()) {
  146. return;
  147. }
  148. std::unique_lock lock{mutex};
  149. bool value_changed = false;
  150. const auto new_status = TransformToButton(callback);
  151. auto& current_status = device_status.keyboard_values[index];
  152. current_status.toggle = new_status.toggle;
  153. // Update button status with current status
  154. if (!current_status.toggle) {
  155. current_status.locked = false;
  156. if (current_status.value != new_status.value) {
  157. current_status.value = new_status.value;
  158. value_changed = true;
  159. }
  160. } else {
  161. // Toggle button and lock status
  162. if (new_status.value && !current_status.locked) {
  163. current_status.locked = true;
  164. current_status.value = !current_status.value;
  165. value_changed = true;
  166. }
  167. // Unlock button, ready for next press
  168. if (!new_status.value && current_status.locked) {
  169. current_status.locked = false;
  170. }
  171. }
  172. if (!value_changed) {
  173. return;
  174. }
  175. if (is_configuring) {
  176. lock.unlock();
  177. TriggerOnChange(DeviceTriggerType::Keyboard);
  178. return;
  179. }
  180. // Index should be converted from NativeKeyboard to KeyboardKeyIndex
  181. UpdateKey(index, current_status.value);
  182. lock.unlock();
  183. TriggerOnChange(DeviceTriggerType::Keyboard);
  184. }
  185. void EmulatedDevices::UpdateKey(std::size_t key_index, bool status) {
  186. constexpr std::size_t KEYS_PER_BYTE = 8;
  187. auto& entry = device_status.keyboard_state.key[key_index / KEYS_PER_BYTE];
  188. const u8 mask = static_cast<u8>(1 << (key_index % KEYS_PER_BYTE));
  189. if (status) {
  190. entry = entry | mask;
  191. } else {
  192. entry = static_cast<u8>(entry & ~mask);
  193. }
  194. }
  195. void EmulatedDevices::SetKeyboardModifier(const Common::Input::CallbackStatus& callback,
  196. std::size_t index) {
  197. if (index >= device_status.keyboard_moddifier_values.size()) {
  198. return;
  199. }
  200. std::unique_lock lock{mutex};
  201. bool value_changed = false;
  202. const auto new_status = TransformToButton(callback);
  203. auto& current_status = device_status.keyboard_moddifier_values[index];
  204. current_status.toggle = new_status.toggle;
  205. // Update button status with current
  206. if (!current_status.toggle) {
  207. current_status.locked = false;
  208. if (current_status.value != new_status.value) {
  209. current_status.value = new_status.value;
  210. value_changed = true;
  211. }
  212. } else {
  213. // Toggle button and lock status
  214. if (new_status.value && !current_status.locked) {
  215. current_status.locked = true;
  216. current_status.value = !current_status.value;
  217. value_changed = true;
  218. }
  219. // Unlock button ready for next press
  220. if (!new_status.value && current_status.locked) {
  221. current_status.locked = false;
  222. }
  223. }
  224. if (!value_changed) {
  225. return;
  226. }
  227. if (is_configuring) {
  228. lock.unlock();
  229. TriggerOnChange(DeviceTriggerType::KeyboardModdifier);
  230. return;
  231. }
  232. switch (index) {
  233. case Settings::NativeKeyboard::LeftControl:
  234. case Settings::NativeKeyboard::RightControl:
  235. device_status.keyboard_moddifier_state.control.Assign(current_status.value);
  236. break;
  237. case Settings::NativeKeyboard::LeftShift:
  238. case Settings::NativeKeyboard::RightShift:
  239. device_status.keyboard_moddifier_state.shift.Assign(current_status.value);
  240. break;
  241. case Settings::NativeKeyboard::LeftAlt:
  242. device_status.keyboard_moddifier_state.left_alt.Assign(current_status.value);
  243. break;
  244. case Settings::NativeKeyboard::RightAlt:
  245. device_status.keyboard_moddifier_state.right_alt.Assign(current_status.value);
  246. break;
  247. case Settings::NativeKeyboard::CapsLock:
  248. device_status.keyboard_moddifier_state.caps_lock.Assign(current_status.value);
  249. break;
  250. case Settings::NativeKeyboard::ScrollLock:
  251. device_status.keyboard_moddifier_state.scroll_lock.Assign(current_status.value);
  252. break;
  253. case Settings::NativeKeyboard::NumLock:
  254. device_status.keyboard_moddifier_state.num_lock.Assign(current_status.value);
  255. break;
  256. }
  257. lock.unlock();
  258. TriggerOnChange(DeviceTriggerType::KeyboardModdifier);
  259. }
  260. void EmulatedDevices::SetMouseButton(const Common::Input::CallbackStatus& callback,
  261. std::size_t index) {
  262. if (index >= device_status.mouse_button_values.size()) {
  263. return;
  264. }
  265. std::unique_lock lock{mutex};
  266. bool value_changed = false;
  267. const auto new_status = TransformToButton(callback);
  268. auto& current_status = device_status.mouse_button_values[index];
  269. current_status.toggle = new_status.toggle;
  270. // Update button status with current
  271. if (!current_status.toggle) {
  272. current_status.locked = false;
  273. if (current_status.value != new_status.value) {
  274. current_status.value = new_status.value;
  275. value_changed = true;
  276. }
  277. } else {
  278. // Toggle button and lock status
  279. if (new_status.value && !current_status.locked) {
  280. current_status.locked = true;
  281. current_status.value = !current_status.value;
  282. value_changed = true;
  283. }
  284. // Unlock button ready for next press
  285. if (!new_status.value && current_status.locked) {
  286. current_status.locked = false;
  287. }
  288. }
  289. if (!value_changed) {
  290. return;
  291. }
  292. if (is_configuring) {
  293. lock.unlock();
  294. TriggerOnChange(DeviceTriggerType::Mouse);
  295. return;
  296. }
  297. switch (index) {
  298. case Settings::NativeMouseButton::Left:
  299. device_status.mouse_button_state.left.Assign(current_status.value);
  300. break;
  301. case Settings::NativeMouseButton::Right:
  302. device_status.mouse_button_state.right.Assign(current_status.value);
  303. break;
  304. case Settings::NativeMouseButton::Middle:
  305. device_status.mouse_button_state.middle.Assign(current_status.value);
  306. break;
  307. case Settings::NativeMouseButton::Forward:
  308. device_status.mouse_button_state.forward.Assign(current_status.value);
  309. break;
  310. case Settings::NativeMouseButton::Back:
  311. device_status.mouse_button_state.back.Assign(current_status.value);
  312. break;
  313. }
  314. lock.unlock();
  315. TriggerOnChange(DeviceTriggerType::Mouse);
  316. }
  317. void EmulatedDevices::SetMouseAnalog(const Common::Input::CallbackStatus& callback,
  318. std::size_t index) {
  319. if (index >= device_status.mouse_analog_values.size()) {
  320. return;
  321. }
  322. std::unique_lock lock{mutex};
  323. const auto analog_value = TransformToAnalog(callback);
  324. device_status.mouse_analog_values[index] = analog_value;
  325. if (is_configuring) {
  326. device_status.mouse_position_state = {};
  327. lock.unlock();
  328. TriggerOnChange(DeviceTriggerType::Mouse);
  329. return;
  330. }
  331. switch (index) {
  332. case Settings::NativeMouseWheel::X:
  333. device_status.mouse_wheel_state.x = static_cast<s32>(analog_value.value);
  334. break;
  335. case Settings::NativeMouseWheel::Y:
  336. device_status.mouse_wheel_state.y = static_cast<s32>(analog_value.value);
  337. break;
  338. }
  339. lock.unlock();
  340. TriggerOnChange(DeviceTriggerType::Mouse);
  341. }
  342. void EmulatedDevices::SetMouseStick(const Common::Input::CallbackStatus& callback) {
  343. std::unique_lock lock{mutex};
  344. const auto touch_value = TransformToTouch(callback);
  345. device_status.mouse_stick_value = touch_value;
  346. if (is_configuring) {
  347. device_status.mouse_position_state = {};
  348. lock.unlock();
  349. TriggerOnChange(DeviceTriggerType::Mouse);
  350. return;
  351. }
  352. device_status.mouse_position_state.x = touch_value.x.value;
  353. device_status.mouse_position_state.y = touch_value.y.value;
  354. lock.unlock();
  355. TriggerOnChange(DeviceTriggerType::Mouse);
  356. }
  357. KeyboardValues EmulatedDevices::GetKeyboardValues() const {
  358. std::scoped_lock lock{mutex};
  359. return device_status.keyboard_values;
  360. }
  361. KeyboardModifierValues EmulatedDevices::GetKeyboardModdifierValues() const {
  362. std::scoped_lock lock{mutex};
  363. return device_status.keyboard_moddifier_values;
  364. }
  365. MouseButtonValues EmulatedDevices::GetMouseButtonsValues() const {
  366. std::scoped_lock lock{mutex};
  367. return device_status.mouse_button_values;
  368. }
  369. KeyboardKey EmulatedDevices::GetKeyboard() const {
  370. std::scoped_lock lock{mutex};
  371. return device_status.keyboard_state;
  372. }
  373. KeyboardModifier EmulatedDevices::GetKeyboardModifier() const {
  374. std::scoped_lock lock{mutex};
  375. return device_status.keyboard_moddifier_state;
  376. }
  377. MouseButton EmulatedDevices::GetMouseButtons() const {
  378. std::scoped_lock lock{mutex};
  379. return device_status.mouse_button_state;
  380. }
  381. MousePosition EmulatedDevices::GetMousePosition() const {
  382. std::scoped_lock lock{mutex};
  383. return device_status.mouse_position_state;
  384. }
  385. AnalogStickState EmulatedDevices::GetMouseWheel() const {
  386. std::scoped_lock lock{mutex};
  387. return device_status.mouse_wheel_state;
  388. }
  389. void EmulatedDevices::TriggerOnChange(DeviceTriggerType type) {
  390. std::scoped_lock lock{callback_mutex};
  391. for (const auto& poller_pair : callback_list) {
  392. const InterfaceUpdateCallback& poller = poller_pair.second;
  393. if (poller.on_change) {
  394. poller.on_change(type);
  395. }
  396. }
  397. }
  398. int EmulatedDevices::SetCallback(InterfaceUpdateCallback update_callback) {
  399. std::scoped_lock lock{callback_mutex};
  400. callback_list.insert_or_assign(last_callback_key, std::move(update_callback));
  401. return last_callback_key++;
  402. }
  403. void EmulatedDevices::DeleteCallback(int key) {
  404. std::scoped_lock lock{callback_mutex};
  405. const auto& iterator = callback_list.find(key);
  406. if (iterator == callback_list.end()) {
  407. LOG_ERROR(Input, "Tried to delete non-existent callback {}", key);
  408. return;
  409. }
  410. callback_list.erase(iterator);
  411. }
  412. } // namespace Core::HID