emulated_devices.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  1. // Copyright 2021 yuzu Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included
  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. const auto& mouse = Settings::values.mouse_buttons;
  12. for (std::size_t index = 0; index < mouse.size(); ++index) {
  13. mouse_button_params[index] = Common::ParamPackage(mouse[index]);
  14. }
  15. ReloadInput();
  16. }
  17. void EmulatedDevices::ReloadInput() {
  18. std::transform(mouse_button_params.begin() + Settings::NativeMouseButton::MOUSE_HID_BEGIN,
  19. mouse_button_params.begin() + Settings::NativeMouseButton::MOUSE_HID_END,
  20. mouse_button_devices.begin(), Input::CreateDevice<Input::InputDevice>);
  21. std::transform(Settings::values.keyboard_keys.begin(), Settings::values.keyboard_keys.end(),
  22. keyboard_devices.begin(), Input::CreateDeviceFromString<Input::InputDevice>);
  23. std::transform(Settings::values.keyboard_mods.begin(), Settings::values.keyboard_mods.end(),
  24. keyboard_modifier_devices.begin(),
  25. Input::CreateDeviceFromString<Input::InputDevice>);
  26. for (std::size_t index = 0; index < mouse_button_devices.size(); ++index) {
  27. if (!mouse_button_devices[index]) {
  28. continue;
  29. }
  30. Input::InputCallback button_callback{
  31. [this, index](Input::CallbackStatus callback) { SetMouseButton(callback, index); }};
  32. mouse_button_devices[index]->SetCallback(button_callback);
  33. }
  34. for (std::size_t index = 0; index < keyboard_devices.size(); ++index) {
  35. if (!keyboard_devices[index]) {
  36. continue;
  37. }
  38. Input::InputCallback button_callback{
  39. [this, index](Input::CallbackStatus callback) { SetKeyboardButton(callback, index); }};
  40. keyboard_devices[index]->SetCallback(button_callback);
  41. }
  42. for (std::size_t index = 0; index < keyboard_modifier_devices.size(); ++index) {
  43. if (!keyboard_modifier_devices[index]) {
  44. continue;
  45. }
  46. Input::InputCallback button_callback{[this, index](Input::CallbackStatus callback) {
  47. SetKeyboardModifier(callback, index);
  48. }};
  49. keyboard_modifier_devices[index]->SetCallback(button_callback);
  50. }
  51. }
  52. void EmulatedDevices::UnloadInput() {
  53. for (auto& button : mouse_button_devices) {
  54. button.reset();
  55. }
  56. for (auto& button : keyboard_devices) {
  57. button.reset();
  58. }
  59. for (auto& button : keyboard_modifier_devices) {
  60. button.reset();
  61. }
  62. }
  63. void EmulatedDevices::EnableConfiguration() {
  64. is_configuring = true;
  65. SaveCurrentConfig();
  66. }
  67. void EmulatedDevices::DisableConfiguration() {
  68. is_configuring = false;
  69. }
  70. bool EmulatedDevices::IsConfiguring() const {
  71. return is_configuring;
  72. }
  73. void EmulatedDevices::SaveCurrentConfig() {
  74. if (!is_configuring) {
  75. return;
  76. }
  77. auto& mouse = Settings::values.mouse_buttons;
  78. for (std::size_t index = 0; index < mouse.size(); ++index) {
  79. mouse[index] = mouse_button_params[index].Serialize();
  80. }
  81. }
  82. void EmulatedDevices::RestoreConfig() {
  83. if (!is_configuring) {
  84. return;
  85. }
  86. ReloadFromSettings();
  87. }
  88. Common::ParamPackage EmulatedDevices::GetMouseButtonParam(std::size_t index) const {
  89. if (index >= mouse_button_params.size()) {
  90. return {};
  91. }
  92. return mouse_button_params[index];
  93. }
  94. void EmulatedDevices::SetMouseButtonParam(std::size_t index, Common::ParamPackage param) {
  95. if (index >= mouse_button_params.size()) {
  96. return;
  97. }
  98. mouse_button_params[index] = param;
  99. ReloadInput();
  100. }
  101. void EmulatedDevices::SetKeyboardButton(Input::CallbackStatus callback, std::size_t index) {
  102. if (index >= device_status.keyboard_values.size()) {
  103. return;
  104. }
  105. std::lock_guard lock{mutex};
  106. bool value_changed = false;
  107. const auto new_status = TransformToButton(callback);
  108. auto& current_status = device_status.keyboard_values[index];
  109. current_status.toggle = new_status.toggle;
  110. // Update button status with current status
  111. if (!current_status.toggle) {
  112. current_status.locked = false;
  113. if (current_status.value != new_status.value) {
  114. current_status.value = new_status.value;
  115. value_changed = true;
  116. }
  117. } else {
  118. // Toggle button and lock status
  119. if (new_status.value && !current_status.locked) {
  120. current_status.locked = true;
  121. current_status.value = !current_status.value;
  122. value_changed = true;
  123. }
  124. // Unlock button, ready for next press
  125. if (!new_status.value && current_status.locked) {
  126. current_status.locked = false;
  127. }
  128. }
  129. if (!value_changed) {
  130. return;
  131. }
  132. if (is_configuring) {
  133. TriggerOnChange(DeviceTriggerType::Keyboard);
  134. return;
  135. }
  136. // TODO(german77): Do this properly
  137. // switch (index) {
  138. // case Settings::NativeKeyboard::A:
  139. // interface_status.keyboard_state.a.Assign(current_status.value);
  140. // break;
  141. // ....
  142. // }
  143. TriggerOnChange(DeviceTriggerType::Keyboard);
  144. }
  145. void EmulatedDevices::SetKeyboardModifier(Input::CallbackStatus callback, std::size_t index) {
  146. if (index >= device_status.keyboard_moddifier_values.size()) {
  147. return;
  148. }
  149. std::lock_guard lock{mutex};
  150. bool value_changed = false;
  151. const auto new_status = TransformToButton(callback);
  152. auto& current_status = device_status.keyboard_moddifier_values[index];
  153. current_status.toggle = new_status.toggle;
  154. // Update button status with current
  155. if (!current_status.toggle) {
  156. current_status.locked = false;
  157. if (current_status.value != new_status.value) {
  158. current_status.value = new_status.value;
  159. value_changed = true;
  160. }
  161. } else {
  162. // Toggle button and lock status
  163. if (new_status.value && !current_status.locked) {
  164. current_status.locked = true;
  165. current_status.value = !current_status.value;
  166. value_changed = true;
  167. }
  168. // Unlock button ready for next press
  169. if (!new_status.value && current_status.locked) {
  170. current_status.locked = false;
  171. }
  172. }
  173. if (!value_changed) {
  174. return;
  175. }
  176. if (is_configuring) {
  177. TriggerOnChange(DeviceTriggerType::KeyboardModdifier);
  178. return;
  179. }
  180. switch (index) {
  181. case Settings::NativeKeyboard::LeftControl:
  182. case Settings::NativeKeyboard::RightControl:
  183. device_status.keyboard_moddifier_state.control.Assign(current_status.value);
  184. break;
  185. case Settings::NativeKeyboard::LeftShift:
  186. case Settings::NativeKeyboard::RightShift:
  187. device_status.keyboard_moddifier_state.shift.Assign(current_status.value);
  188. break;
  189. case Settings::NativeKeyboard::LeftAlt:
  190. device_status.keyboard_moddifier_state.left_alt.Assign(current_status.value);
  191. break;
  192. case Settings::NativeKeyboard::RightAlt:
  193. device_status.keyboard_moddifier_state.right_alt.Assign(current_status.value);
  194. break;
  195. case Settings::NativeKeyboard::CapsLock:
  196. device_status.keyboard_moddifier_state.caps_lock.Assign(current_status.value);
  197. break;
  198. case Settings::NativeKeyboard::ScrollLock:
  199. device_status.keyboard_moddifier_state.scroll_lock.Assign(current_status.value);
  200. break;
  201. case Settings::NativeKeyboard::NumLock:
  202. device_status.keyboard_moddifier_state.num_lock.Assign(current_status.value);
  203. break;
  204. }
  205. TriggerOnChange(DeviceTriggerType::KeyboardModdifier);
  206. }
  207. void EmulatedDevices::SetMouseButton(Input::CallbackStatus callback, std::size_t index) {
  208. if (index >= device_status.mouse_button_values.size()) {
  209. return;
  210. }
  211. std::lock_guard lock{mutex};
  212. bool value_changed = false;
  213. const auto new_status = TransformToButton(callback);
  214. auto& current_status = device_status.mouse_button_values[index];
  215. current_status.toggle = new_status.toggle;
  216. // Update button status with current
  217. if (!current_status.toggle) {
  218. current_status.locked = false;
  219. if (current_status.value != new_status.value) {
  220. current_status.value = new_status.value;
  221. value_changed = true;
  222. }
  223. } else {
  224. // Toggle button and lock status
  225. if (new_status.value && !current_status.locked) {
  226. current_status.locked = true;
  227. current_status.value = !current_status.value;
  228. value_changed = true;
  229. }
  230. // Unlock button ready for next press
  231. if (!new_status.value && current_status.locked) {
  232. current_status.locked = false;
  233. }
  234. }
  235. if (!value_changed) {
  236. return;
  237. }
  238. if (is_configuring) {
  239. TriggerOnChange(DeviceTriggerType::Mouse);
  240. return;
  241. }
  242. switch (index) {
  243. case Settings::NativeMouseButton::Left:
  244. device_status.mouse_button_state.left.Assign(current_status.value);
  245. break;
  246. case Settings::NativeMouseButton::Right:
  247. device_status.mouse_button_state.right.Assign(current_status.value);
  248. break;
  249. case Settings::NativeMouseButton::Middle:
  250. device_status.mouse_button_state.middle.Assign(current_status.value);
  251. break;
  252. case Settings::NativeMouseButton::Forward:
  253. device_status.mouse_button_state.forward.Assign(current_status.value);
  254. break;
  255. case Settings::NativeMouseButton::Back:
  256. device_status.mouse_button_state.back.Assign(current_status.value);
  257. break;
  258. }
  259. TriggerOnChange(DeviceTriggerType::Mouse);
  260. }
  261. KeyboardValues EmulatedDevices::GetKeyboardValues() const {
  262. return device_status.keyboard_values;
  263. }
  264. KeyboardModifierValues EmulatedDevices::GetKeyboardModdifierValues() const {
  265. return device_status.keyboard_moddifier_values;
  266. }
  267. MouseButtonValues EmulatedDevices::GetMouseButtonsValues() const {
  268. return device_status.mouse_button_values;
  269. }
  270. KeyboardKey EmulatedDevices::GetKeyboard() const {
  271. return device_status.keyboard_state;
  272. }
  273. KeyboardModifier EmulatedDevices::GetKeyboardModifier() const {
  274. return device_status.keyboard_moddifier_state;
  275. }
  276. MouseButton EmulatedDevices::GetMouseButtons() const {
  277. return device_status.mouse_button_state;
  278. }
  279. MousePosition EmulatedDevices::GetMousePosition() const {
  280. return device_status.mouse_position_state;
  281. }
  282. void EmulatedDevices::TriggerOnChange(DeviceTriggerType type) {
  283. for (const auto& poller_pair : callback_list) {
  284. const InterfaceUpdateCallback& poller = poller_pair.second;
  285. if (poller.on_change) {
  286. poller.on_change(type);
  287. }
  288. }
  289. }
  290. int EmulatedDevices::SetCallback(InterfaceUpdateCallback update_callback) {
  291. std::lock_guard lock{mutex};
  292. callback_list.insert_or_assign(last_callback_key, update_callback);
  293. return last_callback_key++;
  294. }
  295. void EmulatedDevices::DeleteCallback(int key) {
  296. std::lock_guard lock{mutex};
  297. if (!callback_list.contains(key)) {
  298. LOG_ERROR(Input, "Tried to delete non-existent callback {}", key);
  299. return;
  300. }
  301. callback_list.erase(key);
  302. }
  303. } // namespace Core::HID