| 
									
										
										
										
											2021-09-20 19:43:16 -05:00
										 |  |  | // Copyright 2021 yuzu Emulator Project
 | 
					
						
							|  |  |  | // Licensed under GPLv2 or any later version
 | 
					
						
							|  |  |  | // Refer to the license.txt file included
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-04 19:05:58 -06:00
										 |  |  | #include "common/settings.h"
 | 
					
						
							| 
									
										
										
										
											2021-09-20 19:43:16 -05:00
										 |  |  | #include "core/hid/emulated_console.h"
 | 
					
						
							|  |  |  | #include "core/hid/input_converter.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace Core::HID { | 
					
						
							| 
									
										
										
										
											2021-10-22 23:04:06 -05:00
										 |  |  | EmulatedConsole::EmulatedConsole() = default; | 
					
						
							| 
									
										
										
										
											2021-09-20 19:43:16 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | EmulatedConsole::~EmulatedConsole() = default; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void EmulatedConsole::ReloadFromSettings() { | 
					
						
							| 
									
										
										
										
											2021-11-03 22:35:45 -06:00
										 |  |  |     // Using first motion device from player 1. No need to assign any unique config at the moment
 | 
					
						
							| 
									
										
										
										
											2021-09-20 19:43:16 -05:00
										 |  |  |     const auto& player = Settings::values.players.GetValue()[0]; | 
					
						
							|  |  |  |     motion_params = Common::ParamPackage(player.motions[0]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ReloadInput(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-20 23:18:04 -05:00
										 |  |  | void EmulatedConsole::SetTouchParams() { | 
					
						
							|  |  |  |     // TODO(german77): Support any number of fingers
 | 
					
						
							| 
									
										
										
										
											2021-09-20 19:43:16 -05:00
										 |  |  |     std::size_t index = 0; | 
					
						
							| 
									
										
										
										
											2021-10-20 23:18:04 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // Hardcode mouse, touchscreen and cemuhook parameters
 | 
					
						
							|  |  |  |     touch_params[index++] = Common::ParamPackage{"engine:mouse,axis_x:10,axis_y:11,button:0"}; | 
					
						
							|  |  |  |     touch_params[index++] = Common::ParamPackage{"engine:touch,axis_x:0,axis_y:1,button:0"}; | 
					
						
							|  |  |  |     touch_params[index++] = Common::ParamPackage{"engine:touch,axis_x:2,axis_y:3,button:1"}; | 
					
						
							|  |  |  |     touch_params[index++] = Common::ParamPackage{"engine:cemuhookudp,axis_x:0,axis_y:1,button:0"}; | 
					
						
							|  |  |  |     touch_params[index++] = Common::ParamPackage{"engine:cemuhookudp,axis_x:2,axis_y:3,button:1"}; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-20 19:43:16 -05:00
										 |  |  |     const auto button_index = | 
					
						
							|  |  |  |         static_cast<u64>(Settings::values.touch_from_button_map_index.GetValue()); | 
					
						
							|  |  |  |     const auto& touch_buttons = Settings::values.touch_from_button_maps[button_index].buttons; | 
					
						
							| 
									
										
										
										
											2021-10-20 23:18:04 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-03 22:35:45 -06:00
										 |  |  |     // Map the rest of the fingers from touch from button configuration
 | 
					
						
							| 
									
										
										
										
											2021-09-20 19:43:16 -05:00
										 |  |  |     for (const auto& config_entry : touch_buttons) { | 
					
						
							|  |  |  |         Common::ParamPackage params{config_entry}; | 
					
						
							|  |  |  |         Common::ParamPackage touch_button_params; | 
					
						
							|  |  |  |         const int x = params.Get("x", 0); | 
					
						
							|  |  |  |         const int y = params.Get("y", 0); | 
					
						
							|  |  |  |         params.Erase("x"); | 
					
						
							|  |  |  |         params.Erase("y"); | 
					
						
							|  |  |  |         touch_button_params.Set("engine", "touch_from_button"); | 
					
						
							|  |  |  |         touch_button_params.Set("button", params.Serialize()); | 
					
						
							|  |  |  |         touch_button_params.Set("x", x); | 
					
						
							|  |  |  |         touch_button_params.Set("y", y); | 
					
						
							|  |  |  |         touch_button_params.Set("touch_id", static_cast<int>(index)); | 
					
						
							| 
									
										
										
										
											2021-10-20 23:18:04 -05:00
										 |  |  |         touch_params[index] = touch_button_params; | 
					
						
							|  |  |  |         index++; | 
					
						
							|  |  |  |         if (index >= touch_params.size()) { | 
					
						
							|  |  |  |             return; | 
					
						
							| 
									
										
										
										
											2021-09-20 19:43:16 -05:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-10-20 23:18:04 -05:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2021-09-20 19:43:16 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-20 23:18:04 -05:00
										 |  |  | void EmulatedConsole::ReloadInput() { | 
					
						
							| 
									
										
										
										
											2021-11-03 22:35:45 -06:00
										 |  |  |     // If you load any device here add the equivalent to the UnloadInput() function
 | 
					
						
							| 
									
										
										
										
											2021-10-20 23:18:04 -05:00
										 |  |  |     SetTouchParams(); | 
					
						
							| 
									
										
										
										
											2021-11-03 22:35:45 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-30 22:23:10 -05:00
										 |  |  |     motion_devices = Common::Input::CreateDevice<Common::Input::InputDevice>(motion_params); | 
					
						
							| 
									
										
										
										
											2021-10-20 23:18:04 -05:00
										 |  |  |     if (motion_devices) { | 
					
						
							| 
									
										
										
										
											2021-10-30 22:23:10 -05:00
										 |  |  |         Common::Input::InputCallback motion_callback{ | 
					
						
							|  |  |  |             [this](Common::Input::CallbackStatus callback) { SetMotion(callback); }}; | 
					
						
							| 
									
										
										
										
											2021-10-20 23:18:04 -05:00
										 |  |  |         motion_devices->SetCallback(motion_callback); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-03 22:35:45 -06:00
										 |  |  |     // Unique index for identifying touch device source
 | 
					
						
							| 
									
										
										
										
											2021-10-20 23:18:04 -05:00
										 |  |  |     std::size_t index = 0; | 
					
						
							|  |  |  |     for (auto& touch_device : touch_devices) { | 
					
						
							| 
									
										
										
										
											2021-10-30 22:23:10 -05:00
										 |  |  |         touch_device = Common::Input::CreateDevice<Common::Input::InputDevice>(touch_params[index]); | 
					
						
							| 
									
										
										
										
											2021-10-20 23:18:04 -05:00
										 |  |  |         if (!touch_device) { | 
					
						
							|  |  |  |             continue; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-10-30 22:23:10 -05:00
										 |  |  |         Common::Input::InputCallback touch_callback{ | 
					
						
							|  |  |  |             [this, index](Common::Input::CallbackStatus callback) { SetTouch(callback, index); }}; | 
					
						
							| 
									
										
										
										
											2021-10-20 23:18:04 -05:00
										 |  |  |         touch_device->SetCallback(touch_callback); | 
					
						
							| 
									
										
										
										
											2021-09-20 19:43:16 -05:00
										 |  |  |         index++; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void EmulatedConsole::UnloadInput() { | 
					
						
							|  |  |  |     motion_devices.reset(); | 
					
						
							|  |  |  |     for (auto& touch : touch_devices) { | 
					
						
							|  |  |  |         touch.reset(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void EmulatedConsole::EnableConfiguration() { | 
					
						
							|  |  |  |     is_configuring = true; | 
					
						
							|  |  |  |     SaveCurrentConfig(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void EmulatedConsole::DisableConfiguration() { | 
					
						
							|  |  |  |     is_configuring = false; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool EmulatedConsole::IsConfiguring() const { | 
					
						
							|  |  |  |     return is_configuring; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void EmulatedConsole::SaveCurrentConfig() { | 
					
						
							|  |  |  |     if (!is_configuring) { | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void EmulatedConsole::RestoreConfig() { | 
					
						
							|  |  |  |     if (!is_configuring) { | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     ReloadFromSettings(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Common::ParamPackage EmulatedConsole::GetMotionParam() const { | 
					
						
							|  |  |  |     return motion_params; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void EmulatedConsole::SetMotionParam(Common::ParamPackage param) { | 
					
						
							|  |  |  |     motion_params = param; | 
					
						
							|  |  |  |     ReloadInput(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-30 22:23:10 -05:00
										 |  |  | void EmulatedConsole::SetMotion(Common::Input::CallbackStatus callback) { | 
					
						
							| 
									
										
										
										
											2021-09-20 19:43:16 -05:00
										 |  |  |     std::lock_guard lock{mutex}; | 
					
						
							|  |  |  |     auto& raw_status = console.motion_values.raw_status; | 
					
						
							|  |  |  |     auto& emulated = console.motion_values.emulated; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     raw_status = TransformToMotion(callback); | 
					
						
							|  |  |  |     emulated.SetAcceleration(Common::Vec3f{ | 
					
						
							|  |  |  |         raw_status.accel.x.value, | 
					
						
							|  |  |  |         raw_status.accel.y.value, | 
					
						
							|  |  |  |         raw_status.accel.z.value, | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     emulated.SetGyroscope(Common::Vec3f{ | 
					
						
							|  |  |  |         raw_status.gyro.x.value, | 
					
						
							|  |  |  |         raw_status.gyro.y.value, | 
					
						
							|  |  |  |         raw_status.gyro.z.value, | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     emulated.UpdateRotation(raw_status.delta_timestamp); | 
					
						
							|  |  |  |     emulated.UpdateOrientation(raw_status.delta_timestamp); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (is_configuring) { | 
					
						
							|  |  |  |         TriggerOnChange(ConsoleTriggerType::Motion); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     auto& motion = console.motion_state; | 
					
						
							|  |  |  |     motion.accel = emulated.GetAcceleration(); | 
					
						
							|  |  |  |     motion.gyro = emulated.GetGyroscope(); | 
					
						
							|  |  |  |     motion.rotation = emulated.GetGyroscope(); | 
					
						
							|  |  |  |     motion.orientation = emulated.GetOrientation(); | 
					
						
							|  |  |  |     motion.quaternion = emulated.GetQuaternion(); | 
					
						
							|  |  |  |     motion.is_at_rest = emulated.IsMoving(motion_sensitivity); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     TriggerOnChange(ConsoleTriggerType::Motion); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-30 22:23:10 -05:00
										 |  |  | void EmulatedConsole::SetTouch(Common::Input::CallbackStatus callback, | 
					
						
							|  |  |  |                                [[maybe_unused]] std::size_t index) { | 
					
						
							| 
									
										
										
										
											2021-09-20 19:43:16 -05:00
										 |  |  |     if (index >= console.touch_values.size()) { | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     std::lock_guard lock{mutex}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     console.touch_values[index] = TransformToTouch(callback); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (is_configuring) { | 
					
						
							|  |  |  |         TriggerOnChange(ConsoleTriggerType::Touch); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-31 10:41:44 -05:00
										 |  |  |     // TODO(german77): Remap touch id in sequential order
 | 
					
						
							| 
									
										
										
										
											2021-09-20 19:43:16 -05:00
										 |  |  |     console.touch_state[index] = { | 
					
						
							|  |  |  |         .position = {console.touch_values[index].x.value, console.touch_values[index].y.value}, | 
					
						
							| 
									
										
										
										
											2021-10-31 10:41:44 -05:00
										 |  |  |         .id = static_cast<u32>(console.touch_values[index].id), | 
					
						
							| 
									
										
										
										
											2021-09-20 19:43:16 -05:00
										 |  |  |         .pressed = console.touch_values[index].pressed.value, | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     TriggerOnChange(ConsoleTriggerType::Touch); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ConsoleMotionValues EmulatedConsole::GetMotionValues() const { | 
					
						
							|  |  |  |     return console.motion_values; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | TouchValues EmulatedConsole::GetTouchValues() const { | 
					
						
							|  |  |  |     return console.touch_values; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ConsoleMotion EmulatedConsole::GetMotion() const { | 
					
						
							|  |  |  |     return console.motion_state; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | TouchFingerState EmulatedConsole::GetTouch() const { | 
					
						
							|  |  |  |     return console.touch_state; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void EmulatedConsole::TriggerOnChange(ConsoleTriggerType type) { | 
					
						
							| 
									
										
										
										
											2021-10-22 23:04:06 -05:00
										 |  |  |     for (const auto& poller_pair : callback_list) { | 
					
						
							| 
									
										
										
										
											2021-09-20 19:43:16 -05:00
										 |  |  |         const ConsoleUpdateCallback& poller = poller_pair.second; | 
					
						
							|  |  |  |         if (poller.on_change) { | 
					
						
							|  |  |  |             poller.on_change(type); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int EmulatedConsole::SetCallback(ConsoleUpdateCallback update_callback) { | 
					
						
							|  |  |  |     std::lock_guard lock{mutex}; | 
					
						
							|  |  |  |     callback_list.insert_or_assign(last_callback_key, update_callback); | 
					
						
							|  |  |  |     return last_callback_key++; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void EmulatedConsole::DeleteCallback(int key) { | 
					
						
							|  |  |  |     std::lock_guard lock{mutex}; | 
					
						
							| 
									
										
										
										
											2021-11-01 14:17:53 -06:00
										 |  |  |     const auto& iterator = callback_list.find(key); | 
					
						
							|  |  |  |     if (iterator == callback_list.end()) { | 
					
						
							| 
									
										
										
										
											2021-09-20 19:43:16 -05:00
										 |  |  |         LOG_ERROR(Input, "Tried to delete non-existent callback {}", key); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-11-01 14:17:53 -06:00
										 |  |  |     callback_list.erase(iterator); | 
					
						
							| 
									
										
										
										
											2021-09-20 19:43:16 -05:00
										 |  |  | } | 
					
						
							|  |  |  | } // namespace Core::HID
 |