Compare commits
	
		
			1 Commits
		
	
	
		
			system-con
			...
			be_my_frie
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 43a7bd18b2 | 
| @@ -159,8 +159,6 @@ add_library(core STATIC | ||||
|     hid/irs_types.h | ||||
|     hid/motion_input.cpp | ||||
|     hid/motion_input.h | ||||
|     hid/system_controller.cpp | ||||
|     hid/system_controller.h | ||||
|     hle/api_version.h | ||||
|     hle/ipc.h | ||||
|     hle/kernel/board/nintendo/nx/k_memory_layout.cpp | ||||
| @@ -461,8 +459,12 @@ add_library(core STATIC | ||||
|     hle/service/fgm/fgm.h | ||||
|     hle/service/friend/friend.cpp | ||||
|     hle/service/friend/friend.h | ||||
|     hle/service/friend/friend_interface.cpp | ||||
|     hle/service/friend/friend_interface.h | ||||
|     hle/service/friend/friend_results.h | ||||
|     hle/service/friend/friend_service.cpp | ||||
|     hle/service/friend/friend_service.h | ||||
|     hle/service/friend/friend_types.h | ||||
|     hle/service/friend/notification_service.cpp | ||||
|     hle/service/friend/notification_service.h | ||||
|     hle/service/glue/arp.cpp | ||||
|     hle/service/glue/arp.h | ||||
|     hle/service/glue/bgtc.cpp | ||||
|   | ||||
| @@ -46,26 +46,26 @@ void DefaultControllerApplet::ReconfigureControllers(ReconfigureCallback callbac | ||||
|         // Pro Controller -> Dual Joycons -> Left Joycon/Right Joycon -> Handheld | ||||
|         if (parameters.allow_pro_controller) { | ||||
|             controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::ProController); | ||||
|             controller->Connect(); | ||||
|             controller->Connect(true); | ||||
|         } else if (parameters.allow_dual_joycons) { | ||||
|             controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::JoyconDual); | ||||
|             controller->Connect(); | ||||
|             controller->Connect(true); | ||||
|         } else if (parameters.allow_left_joycon && parameters.allow_right_joycon) { | ||||
|             // Assign left joycons to even player indices and right joycons to odd player indices. | ||||
|             // We do this since Captain Toad Treasure Tracker expects a left joycon for Player 1 and | ||||
|             // a right Joycon for Player 2 in 2 Player Assist mode. | ||||
|             if (index % 2 == 0) { | ||||
|                 controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::JoyconLeft); | ||||
|                 controller->Connect(); | ||||
|                 controller->Connect(true); | ||||
|             } else { | ||||
|                 controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::JoyconRight); | ||||
|                 controller->Connect(); | ||||
|                 controller->Connect(true); | ||||
|             } | ||||
|         } else if (index == 0 && parameters.enable_single_mode && parameters.allow_handheld && | ||||
|                    !Settings::values.use_docked_mode.GetValue()) { | ||||
|             // We should *never* reach here under any normal circumstances. | ||||
|             controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::Handheld); | ||||
|             controller->Connect(); | ||||
|             controller->Connect(true); | ||||
|         } else { | ||||
|             ASSERT_MSG(false, "Unable to add a new controller based on the given parameters!"); | ||||
|         } | ||||
|   | ||||
| @@ -95,6 +95,7 @@ void EmulatedController::ReloadFromSettings() { | ||||
|         motion_params[index] = Common::ParamPackage(player.motions[index]); | ||||
|     } | ||||
|  | ||||
|     controller.color_values = {}; | ||||
|     controller.colors_state.fullkey = { | ||||
|         .body = GetNpadColor(player.body_color_left), | ||||
|         .button = GetNpadColor(player.button_color_left), | ||||
| @@ -536,18 +537,181 @@ void EmulatedController::UnloadInput() { | ||||
|     } | ||||
| } | ||||
|  | ||||
| void EmulatedController::DisableInput() { | ||||
|     npad_input_enabled = false; | ||||
| void EmulatedController::EnableConfiguration() { | ||||
|     is_configuring = true; | ||||
|     tmp_is_connected = is_connected; | ||||
|     tmp_npad_type = npad_type; | ||||
| } | ||||
|  | ||||
| void EmulatedController::EnableInput() { | ||||
|     npad_input_enabled = true; | ||||
| void EmulatedController::DisableConfiguration() { | ||||
|     is_configuring = false; | ||||
|  | ||||
|     // Get Joycon colors before turning on the controller | ||||
|     for (const auto& color_device : color_devices) { | ||||
|         color_device->ForceUpdate(); | ||||
|     } | ||||
|  | ||||
|     // Apply temporary npad type to the real controller | ||||
|     if (tmp_npad_type != npad_type) { | ||||
|         if (is_connected) { | ||||
|             Disconnect(); | ||||
|         } | ||||
|         SetNpadStyleIndex(tmp_npad_type); | ||||
|         original_npad_type = tmp_npad_type; | ||||
|     } | ||||
|  | ||||
|     // Apply temporary connected status to the real controller | ||||
|     if (tmp_is_connected != is_connected) { | ||||
|         if (tmp_is_connected) { | ||||
|             Connect(); | ||||
|             return; | ||||
|         } | ||||
|         Disconnect(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void EmulatedController::EnableSystemButtons() { | ||||
|     std::scoped_lock lock{mutex}; | ||||
|     system_buttons_enabled = true; | ||||
| } | ||||
|  | ||||
| void EmulatedController::DisableSystemButtons() { | ||||
|     std::scoped_lock lock{mutex}; | ||||
|     system_buttons_enabled = false; | ||||
|     controller.home_button_state.raw = 0; | ||||
|     controller.capture_button_state.raw = 0; | ||||
| } | ||||
|  | ||||
| void EmulatedController::ResetSystemButtons() { | ||||
|     std::scoped_lock lock{mutex}; | ||||
|     controller.home_button_state.home.Assign(false); | ||||
|     controller.capture_button_state.capture.Assign(false); | ||||
| } | ||||
|  | ||||
| bool EmulatedController::IsConfiguring() const { | ||||
|     return is_configuring; | ||||
| } | ||||
|  | ||||
| void EmulatedController::SaveCurrentConfig() { | ||||
|     const auto player_index = NpadIdTypeToIndex(npad_id_type); | ||||
|     auto& player = Settings::values.players.GetValue()[player_index]; | ||||
|     player.connected = is_connected; | ||||
|     player.controller_type = MapNPadToSettingsType(npad_type); | ||||
|     for (std::size_t index = 0; index < player.buttons.size(); ++index) { | ||||
|         player.buttons[index] = button_params[index].Serialize(); | ||||
|     } | ||||
|     for (std::size_t index = 0; index < player.analogs.size(); ++index) { | ||||
|         player.analogs[index] = stick_params[index].Serialize(); | ||||
|     } | ||||
|     for (std::size_t index = 0; index < player.motions.size(); ++index) { | ||||
|         player.motions[index] = motion_params[index].Serialize(); | ||||
|     } | ||||
|     if (npad_id_type == NpadIdType::Player1) { | ||||
|         Settings::values.ringcon_analogs = ring_params[0].Serialize(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void EmulatedController::RestoreConfig() { | ||||
|     if (!is_configuring) { | ||||
|         return; | ||||
|     } | ||||
|     ReloadFromSettings(); | ||||
| } | ||||
|  | ||||
| std::vector<Common::ParamPackage> EmulatedController::GetMappedDevices() const { | ||||
|     std::vector<Common::ParamPackage> devices; | ||||
|     for (const auto& param : button_params) { | ||||
|         if (!param.Has("engine")) { | ||||
|             continue; | ||||
|         } | ||||
|         const auto devices_it = std::find_if( | ||||
|             devices.begin(), devices.end(), [¶m](const Common::ParamPackage& param_) { | ||||
|                 return param.Get("engine", "") == param_.Get("engine", "") && | ||||
|                        param.Get("guid", "") == param_.Get("guid", "") && | ||||
|                        param.Get("port", 0) == param_.Get("port", 0) && | ||||
|                        param.Get("pad", 0) == param_.Get("pad", 0); | ||||
|             }); | ||||
|         if (devices_it != devices.end()) { | ||||
|             continue; | ||||
|         } | ||||
|  | ||||
|         auto& device = devices.emplace_back(); | ||||
|         device.Set("engine", param.Get("engine", "")); | ||||
|         device.Set("guid", param.Get("guid", "")); | ||||
|         device.Set("port", param.Get("port", 0)); | ||||
|         device.Set("pad", param.Get("pad", 0)); | ||||
|     } | ||||
|  | ||||
|     for (const auto& param : stick_params) { | ||||
|         if (!param.Has("engine")) { | ||||
|             continue; | ||||
|         } | ||||
|         if (param.Get("engine", "") == "analog_from_button") { | ||||
|             continue; | ||||
|         } | ||||
|         const auto devices_it = std::find_if( | ||||
|             devices.begin(), devices.end(), [¶m](const Common::ParamPackage& param_) { | ||||
|                 return param.Get("engine", "") == param_.Get("engine", "") && | ||||
|                        param.Get("guid", "") == param_.Get("guid", "") && | ||||
|                        param.Get("port", 0) == param_.Get("port", 0) && | ||||
|                        param.Get("pad", 0) == param_.Get("pad", 0); | ||||
|             }); | ||||
|         if (devices_it != devices.end()) { | ||||
|             continue; | ||||
|         } | ||||
|  | ||||
|         auto& device = devices.emplace_back(); | ||||
|         device.Set("engine", param.Get("engine", "")); | ||||
|         device.Set("guid", param.Get("guid", "")); | ||||
|         device.Set("port", param.Get("port", 0)); | ||||
|         device.Set("pad", param.Get("pad", 0)); | ||||
|     } | ||||
|     return devices; | ||||
| } | ||||
|  | ||||
| Common::ParamPackage EmulatedController::GetButtonParam(std::size_t index) const { | ||||
|     if (index >= button_params.size()) { | ||||
|         return {}; | ||||
|     } | ||||
|     return button_params[index]; | ||||
| } | ||||
|  | ||||
| Common::ParamPackage EmulatedController::GetStickParam(std::size_t index) const { | ||||
|     if (index >= stick_params.size()) { | ||||
|         return {}; | ||||
|     } | ||||
|     return stick_params[index]; | ||||
| } | ||||
|  | ||||
| Common::ParamPackage EmulatedController::GetMotionParam(std::size_t index) const { | ||||
|     if (index >= motion_params.size()) { | ||||
|         return {}; | ||||
|     } | ||||
|     return motion_params[index]; | ||||
| } | ||||
|  | ||||
| void EmulatedController::SetButtonParam(std::size_t index, Common::ParamPackage param) { | ||||
|     if (index >= button_params.size()) { | ||||
|         return; | ||||
|     } | ||||
|     button_params[index] = std::move(param); | ||||
|     ReloadInput(); | ||||
| } | ||||
|  | ||||
| void EmulatedController::SetStickParam(std::size_t index, Common::ParamPackage param) { | ||||
|     if (index >= stick_params.size()) { | ||||
|         return; | ||||
|     } | ||||
|     stick_params[index] = std::move(param); | ||||
|     ReloadInput(); | ||||
| } | ||||
|  | ||||
| void EmulatedController::SetMotionParam(std::size_t index, Common::ParamPackage param) { | ||||
|     if (index >= motion_params.size()) { | ||||
|         return; | ||||
|     } | ||||
|     motion_params[index] = std::move(param); | ||||
|     ReloadInput(); | ||||
| } | ||||
|  | ||||
| void EmulatedController::StartMotionCalibration() { | ||||
| @@ -602,6 +766,16 @@ void EmulatedController::SetButton(const Common::Input::CallbackStatus& callback | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     if (is_configuring) { | ||||
|         controller.npad_button_state.raw = NpadButton::None; | ||||
|         controller.debug_pad_button_state.raw = 0; | ||||
|         controller.home_button_state.raw = 0; | ||||
|         controller.capture_button_state.raw = 0; | ||||
|         lock.unlock(); | ||||
|         TriggerOnChange(ControllerTriggerType::Button, false); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     // GC controllers have triggers not buttons | ||||
|     if (npad_type == NpadStyleIndex::GameCube) { | ||||
|         if (index == Settings::NativeButton::ZR) { | ||||
| @@ -683,6 +857,18 @@ void EmulatedController::SetButton(const Common::Input::CallbackStatus& callback | ||||
|         controller.npad_button_state.left_sr.Assign(current_status.value); | ||||
|         controller.npad_button_state.right_sr.Assign(current_status.value); | ||||
|         break; | ||||
|     case Settings::NativeButton::Home: | ||||
|         if (!system_buttons_enabled) { | ||||
|             break; | ||||
|         } | ||||
|         controller.home_button_state.home.Assign(current_status.value); | ||||
|         break; | ||||
|     case Settings::NativeButton::Screenshot: | ||||
|         if (!system_buttons_enabled) { | ||||
|             break; | ||||
|         } | ||||
|         controller.capture_button_state.capture.Assign(current_status.value); | ||||
|         break; | ||||
|     } | ||||
|  | ||||
|     lock.unlock(); | ||||
| @@ -695,7 +881,7 @@ void EmulatedController::SetButton(const Common::Input::CallbackStatus& callback | ||||
|             Connect(); | ||||
|         } | ||||
|     } | ||||
|     TriggerOnChange(ControllerTriggerType::Button); | ||||
|     TriggerOnChange(ControllerTriggerType::Button, true); | ||||
| } | ||||
|  | ||||
| void EmulatedController::SetStick(const Common::Input::CallbackStatus& callback, std::size_t index, | ||||
| @@ -704,7 +890,7 @@ void EmulatedController::SetStick(const Common::Input::CallbackStatus& callback, | ||||
|         return; | ||||
|     } | ||||
|     auto trigger_guard = | ||||
|         SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Stick); }); | ||||
|         SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Stick, !is_configuring); }); | ||||
|     std::scoped_lock lock{mutex}; | ||||
|     const auto stick_value = TransformToStick(callback); | ||||
|  | ||||
| @@ -725,6 +911,12 @@ void EmulatedController::SetStick(const Common::Input::CallbackStatus& callback, | ||||
|     controller.stick_values[index] = stick_value; | ||||
|     controller.stick_values[index].uuid = uuid; | ||||
|  | ||||
|     if (is_configuring) { | ||||
|         controller.analog_stick_state.left = {}; | ||||
|         controller.analog_stick_state.right = {}; | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     const AnalogStickState stick{ | ||||
|         .x = static_cast<s32>(controller.stick_values[index].x.value * HID_JOYSTICK_MAX), | ||||
|         .y = static_cast<s32>(controller.stick_values[index].y.value * HID_JOYSTICK_MAX), | ||||
| @@ -754,7 +946,7 @@ void EmulatedController::SetTrigger(const Common::Input::CallbackStatus& callbac | ||||
|         return; | ||||
|     } | ||||
|     auto trigger_guard = | ||||
|         SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Trigger); }); | ||||
|         SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Trigger, !is_configuring); }); | ||||
|     std::scoped_lock lock{mutex}; | ||||
|     const auto trigger_value = TransformToTrigger(callback); | ||||
|  | ||||
| @@ -768,6 +960,12 @@ void EmulatedController::SetTrigger(const Common::Input::CallbackStatus& callbac | ||||
|     controller.trigger_values[index] = trigger_value; | ||||
|     controller.trigger_values[index].uuid = uuid; | ||||
|  | ||||
|     if (is_configuring) { | ||||
|         controller.gc_trigger_state.left = 0; | ||||
|         controller.gc_trigger_state.right = 0; | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     // Only GC controllers have analog triggers | ||||
|     if (npad_type != NpadStyleIndex::GameCube) { | ||||
|         trigger_guard.Cancel(); | ||||
| @@ -794,7 +992,7 @@ void EmulatedController::SetMotion(const Common::Input::CallbackStatus& callback | ||||
|     if (index >= controller.motion_values.size()) { | ||||
|         return; | ||||
|     } | ||||
|     SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::Motion); }); | ||||
|     SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::Motion, !is_configuring); }); | ||||
|     std::scoped_lock lock{mutex}; | ||||
|     auto& raw_status = controller.motion_values[index].raw_status; | ||||
|     auto& emulated = controller.motion_values[index].emulated; | ||||
| @@ -825,44 +1023,48 @@ void EmulatedController::SetMotion(const Common::Input::CallbackStatus& callback | ||||
|  | ||||
| void EmulatedController::SetColors(const Common::Input::CallbackStatus& callback, | ||||
|                                    std::size_t index) { | ||||
|     if (index > RightIndex) { | ||||
|     if (index >= controller.color_values.size()) { | ||||
|         return; | ||||
|     } | ||||
|     auto trigger_guard = | ||||
|         SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Color); }); | ||||
|         SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Color, !is_configuring); }); | ||||
|     std::scoped_lock lock{mutex}; | ||||
|     const auto color_values = TransformToColor(callback); | ||||
|     controller.color_values[index] = TransformToColor(callback); | ||||
|  | ||||
|     if (color_values.body == 0) { | ||||
|     if (is_configuring) { | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     if (controller.color_values[index].body == 0) { | ||||
|         trigger_guard.Cancel(); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     controller.colors_state.fullkey = { | ||||
|         .body = GetNpadColor(color_values.body), | ||||
|         .button = GetNpadColor(color_values.buttons), | ||||
|         .body = GetNpadColor(controller.color_values[index].body), | ||||
|         .button = GetNpadColor(controller.color_values[index].buttons), | ||||
|     }; | ||||
|     if (npad_type == NpadStyleIndex::ProController) { | ||||
|         controller.colors_state.left = { | ||||
|             .body = GetNpadColor(color_values.left_grip), | ||||
|             .button = GetNpadColor(color_values.buttons), | ||||
|             .body = GetNpadColor(controller.color_values[index].left_grip), | ||||
|             .button = GetNpadColor(controller.color_values[index].buttons), | ||||
|         }; | ||||
|         controller.colors_state.right = { | ||||
|             .body = GetNpadColor(color_values.right_grip), | ||||
|             .button = GetNpadColor(color_values.buttons), | ||||
|             .body = GetNpadColor(controller.color_values[index].right_grip), | ||||
|             .button = GetNpadColor(controller.color_values[index].buttons), | ||||
|         }; | ||||
|     } else { | ||||
|         switch (index) { | ||||
|         case LeftIndex: | ||||
|             controller.colors_state.left = { | ||||
|                 .body = GetNpadColor(color_values.body), | ||||
|                 .button = GetNpadColor(color_values.buttons), | ||||
|                 .body = GetNpadColor(controller.color_values[index].body), | ||||
|                 .button = GetNpadColor(controller.color_values[index].buttons), | ||||
|             }; | ||||
|             break; | ||||
|         case RightIndex: | ||||
|             controller.colors_state.right = { | ||||
|                 .body = GetNpadColor(color_values.body), | ||||
|                 .button = GetNpadColor(color_values.buttons), | ||||
|                 .body = GetNpadColor(controller.color_values[index].body), | ||||
|                 .button = GetNpadColor(controller.color_values[index].buttons), | ||||
|             }; | ||||
|             break; | ||||
|         } | ||||
| @@ -871,17 +1073,21 @@ void EmulatedController::SetColors(const Common::Input::CallbackStatus& callback | ||||
|  | ||||
| void EmulatedController::SetBattery(const Common::Input::CallbackStatus& callback, | ||||
|                                     std::size_t index) { | ||||
|     if (index > DualIndex) { | ||||
|     if (index >= controller.battery_values.size()) { | ||||
|         return; | ||||
|     } | ||||
|     SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::Battery); }); | ||||
|     SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::Battery, !is_configuring); }); | ||||
|     std::scoped_lock lock{mutex}; | ||||
|     const auto battery_values = TransformToBattery(callback); | ||||
|     controller.battery_values[index] = TransformToBattery(callback); | ||||
|  | ||||
|     if (is_configuring) { | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     bool is_charging = false; | ||||
|     bool is_powered = false; | ||||
|     NpadBatteryLevel battery_level = 0; | ||||
|     switch (battery_values) { | ||||
|     switch (controller.battery_values[index]) { | ||||
|     case Common::Input::BatteryLevel::Charging: | ||||
|         is_charging = true; | ||||
|         is_powered = true; | ||||
| @@ -933,33 +1139,46 @@ void EmulatedController::SetBattery(const Common::Input::CallbackStatus& callbac | ||||
| } | ||||
|  | ||||
| void EmulatedController::SetCamera(const Common::Input::CallbackStatus& callback) { | ||||
|     SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::IrSensor); }); | ||||
|     SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::IrSensor, !is_configuring); }); | ||||
|     std::scoped_lock lock{mutex}; | ||||
|     const auto camera_values = TransformToCamera(callback); | ||||
|     controller.camera_values = TransformToCamera(callback); | ||||
|  | ||||
|     if (is_configuring) { | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     controller.camera_state.sample++; | ||||
|     controller.camera_state.format = | ||||
|         static_cast<Core::IrSensor::ImageTransferProcessorFormat>(camera_values.format); | ||||
|     controller.camera_state.data = camera_values.data; | ||||
|         static_cast<Core::IrSensor::ImageTransferProcessorFormat>(controller.camera_values.format); | ||||
|     controller.camera_state.data = controller.camera_values.data; | ||||
| } | ||||
|  | ||||
| void EmulatedController::SetRingAnalog(const Common::Input::CallbackStatus& callback) { | ||||
|     SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::RingController); }); | ||||
|     SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::RingController, !is_configuring); }); | ||||
|     std::scoped_lock lock{mutex}; | ||||
|     const auto force_value = TransformToStick(callback); | ||||
|  | ||||
|     controller.ring_analog_value = force_value.x; | ||||
|  | ||||
|     if (is_configuring) { | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     controller.ring_analog_state.force = force_value.x.value; | ||||
| } | ||||
|  | ||||
| void EmulatedController::SetNfc(const Common::Input::CallbackStatus& callback) { | ||||
|     SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::Nfc); }); | ||||
|     SCOPE_EXIT({ TriggerOnChange(ControllerTriggerType::Nfc, !is_configuring); }); | ||||
|     std::scoped_lock lock{mutex}; | ||||
|     const auto nfc_values = TransformToNfc(callback); | ||||
|     controller.nfc_values = TransformToNfc(callback); | ||||
|  | ||||
|     if (is_configuring) { | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     controller.nfc_state = { | ||||
|         nfc_values.state, | ||||
|         nfc_values.data, | ||||
|         controller.nfc_values.state, | ||||
|         controller.nfc_values.data, | ||||
|     }; | ||||
| } | ||||
|  | ||||
| @@ -1190,9 +1409,10 @@ void EmulatedController::SetSupportedNpadStyleTag(NpadStyleTag supported_styles) | ||||
|               npad_type); | ||||
| } | ||||
|  | ||||
| bool EmulatedController::IsControllerFullkey() const { | ||||
| bool EmulatedController::IsControllerFullkey(bool use_temporary_value) const { | ||||
|     std::scoped_lock lock{mutex}; | ||||
|     switch (npad_type) { | ||||
|     const auto type = is_configuring && use_temporary_value ? tmp_npad_type : npad_type; | ||||
|     switch (type) { | ||||
|     case NpadStyleIndex::ProController: | ||||
|     case NpadStyleIndex::GameCube: | ||||
|     case NpadStyleIndex::NES: | ||||
| @@ -1205,9 +1425,10 @@ bool EmulatedController::IsControllerFullkey() const { | ||||
|     } | ||||
| } | ||||
|  | ||||
| bool EmulatedController::IsControllerSupported() const { | ||||
| bool EmulatedController::IsControllerSupported(bool use_temporary_value) const { | ||||
|     std::scoped_lock lock{mutex}; | ||||
|     switch (npad_type) { | ||||
|     const auto type = is_configuring && use_temporary_value ? tmp_npad_type : npad_type; | ||||
|     switch (type) { | ||||
|     case NpadStyleIndex::ProController: | ||||
|         return supported_style_tag.fullkey.As<bool>(); | ||||
|     case NpadStyleIndex::Handheld: | ||||
| @@ -1235,15 +1456,20 @@ bool EmulatedController::IsControllerSupported() const { | ||||
|     } | ||||
| } | ||||
|  | ||||
| void EmulatedController::Connect() { | ||||
|     if (!IsControllerSupported()) { | ||||
|         LOG_ERROR(Service_HID, "Controller type {} is not supported", npad_type); | ||||
| void EmulatedController::Connect(bool use_temporary_value) { | ||||
|     if (!IsControllerSupported(use_temporary_value)) { | ||||
|         const auto type = is_configuring && use_temporary_value ? tmp_npad_type : npad_type; | ||||
|         LOG_ERROR(Service_HID, "Controller type {} is not supported", type); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     auto trigger_guard = | ||||
|         SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Connected); }); | ||||
|         SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Connected, !is_configuring); }); | ||||
|     std::scoped_lock lock{mutex}; | ||||
|     if (is_configuring) { | ||||
|         tmp_is_connected = true; | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     if (is_connected) { | ||||
|         trigger_guard.Cancel(); | ||||
| @@ -1254,8 +1480,12 @@ void EmulatedController::Connect() { | ||||
|  | ||||
| void EmulatedController::Disconnect() { | ||||
|     auto trigger_guard = | ||||
|         SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Disconnected); }); | ||||
|         SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Disconnected, !is_configuring); }); | ||||
|     std::scoped_lock lock{mutex}; | ||||
|     if (is_configuring) { | ||||
|         tmp_is_connected = false; | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     if (!is_connected) { | ||||
|         trigger_guard.Cancel(); | ||||
| @@ -1264,8 +1494,11 @@ void EmulatedController::Disconnect() { | ||||
|     is_connected = false; | ||||
| } | ||||
|  | ||||
| bool EmulatedController::IsConnected() const { | ||||
| bool EmulatedController::IsConnected(bool get_temporary_value) const { | ||||
|     std::scoped_lock lock{mutex}; | ||||
|     if (get_temporary_value && is_configuring) { | ||||
|         return tmp_is_connected; | ||||
|     } | ||||
|     return is_connected; | ||||
| } | ||||
|  | ||||
| @@ -1275,14 +1508,27 @@ NpadIdType EmulatedController::GetNpadIdType() const { | ||||
| } | ||||
|  | ||||
| NpadStyleIndex EmulatedController::GetNpadStyleIndex(bool get_temporary_value) const { | ||||
|     std::scoped_lock lock{mutex}; | ||||
|     if (get_temporary_value && is_configuring) { | ||||
|         return tmp_npad_type; | ||||
|     } | ||||
|     return npad_type; | ||||
| } | ||||
|  | ||||
| void EmulatedController::SetNpadStyleIndex(NpadStyleIndex npad_type_) { | ||||
|     auto trigger_guard = | ||||
|         SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Type); }); | ||||
|         SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Type, !is_configuring); }); | ||||
|     std::scoped_lock lock{mutex}; | ||||
|  | ||||
|     if (is_configuring) { | ||||
|         if (tmp_npad_type == npad_type_) { | ||||
|             trigger_guard.Cancel(); | ||||
|             return; | ||||
|         } | ||||
|         tmp_npad_type = npad_type_; | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     if (npad_type == npad_type_) { | ||||
|         trigger_guard.Cancel(); | ||||
|         return; | ||||
| @@ -1322,23 +1568,87 @@ ButtonValues EmulatedController::GetButtonsValues() const { | ||||
|     return controller.button_values; | ||||
| } | ||||
|  | ||||
| SticksValues EmulatedController::GetSticksValues() const { | ||||
|     std::scoped_lock lock{mutex}; | ||||
|     return controller.stick_values; | ||||
| } | ||||
|  | ||||
| TriggerValues EmulatedController::GetTriggersValues() const { | ||||
|     std::scoped_lock lock{mutex}; | ||||
|     return controller.trigger_values; | ||||
| } | ||||
|  | ||||
| ControllerMotionValues EmulatedController::GetMotionValues() const { | ||||
|     std::scoped_lock lock{mutex}; | ||||
|     return controller.motion_values; | ||||
| } | ||||
|  | ||||
| ColorValues EmulatedController::GetColorsValues() const { | ||||
|     std::scoped_lock lock{mutex}; | ||||
|     return controller.color_values; | ||||
| } | ||||
|  | ||||
| BatteryValues EmulatedController::GetBatteryValues() const { | ||||
|     std::scoped_lock lock{mutex}; | ||||
|     return controller.battery_values; | ||||
| } | ||||
|  | ||||
| CameraValues EmulatedController::GetCameraValues() const { | ||||
|     std::scoped_lock lock{mutex}; | ||||
|     return controller.camera_values; | ||||
| } | ||||
|  | ||||
| RingAnalogValue EmulatedController::GetRingSensorValues() const { | ||||
|     return controller.ring_analog_value; | ||||
| } | ||||
|  | ||||
| HomeButtonState EmulatedController::GetHomeButtons() const { | ||||
|     std::scoped_lock lock{mutex}; | ||||
|     if (is_configuring) { | ||||
|         return {}; | ||||
|     } | ||||
|     return controller.home_button_state; | ||||
| } | ||||
|  | ||||
| CaptureButtonState EmulatedController::GetCaptureButtons() const { | ||||
|     std::scoped_lock lock{mutex}; | ||||
|     if (is_configuring) { | ||||
|         return {}; | ||||
|     } | ||||
|     return controller.capture_button_state; | ||||
| } | ||||
|  | ||||
| NpadButtonState EmulatedController::GetNpadButtons() const { | ||||
|     std::scoped_lock lock{mutex}; | ||||
|     if (is_configuring) { | ||||
|         return {}; | ||||
|     } | ||||
|     return {controller.npad_button_state.raw & GetTurboButtonMask()}; | ||||
| } | ||||
|  | ||||
| DebugPadButton EmulatedController::GetDebugPadButtons() const { | ||||
|     std::scoped_lock lock{mutex}; | ||||
|     if (is_configuring) { | ||||
|         return {}; | ||||
|     } | ||||
|     return controller.debug_pad_button_state; | ||||
| } | ||||
|  | ||||
| AnalogSticks EmulatedController::GetSticks() const { | ||||
|     std::scoped_lock lock{mutex}; | ||||
|  | ||||
|     if (is_configuring) { | ||||
|         return {}; | ||||
|     } | ||||
|  | ||||
|     return controller.analog_stick_state; | ||||
| } | ||||
|  | ||||
| NpadGcTriggerState EmulatedController::GetTriggers() const { | ||||
|     std::scoped_lock lock{mutex}; | ||||
|     if (is_configuring) { | ||||
|         return {}; | ||||
|     } | ||||
|     return controller.gc_trigger_state; | ||||
| } | ||||
|  | ||||
| @@ -1363,7 +1673,6 @@ const CameraState& EmulatedController::GetCamera() const { | ||||
| } | ||||
|  | ||||
| RingSensorForce EmulatedController::GetRingSensorForce() const { | ||||
|     std::scoped_lock lock{mutex}; | ||||
|     return controller.ring_analog_state; | ||||
| } | ||||
|  | ||||
| @@ -1381,10 +1690,13 @@ NpadColor EmulatedController::GetNpadColor(u32 color) { | ||||
|     }; | ||||
| } | ||||
|  | ||||
| void EmulatedController::TriggerOnChange(ControllerTriggerType type) { | ||||
| void EmulatedController::TriggerOnChange(ControllerTriggerType type, bool is_npad_service_update) { | ||||
|     std::scoped_lock lock{callback_mutex}; | ||||
|     for (const auto& poller_pair : callback_list) { | ||||
|         const ControllerUpdateCallback& poller = poller_pair.second; | ||||
|         if (!is_npad_service_update && poller.is_npad_service) { | ||||
|             continue; | ||||
|         } | ||||
|         if (poller.on_change) { | ||||
|             poller.on_change(type); | ||||
|         } | ||||
|   | ||||
| @@ -126,8 +126,16 @@ struct ControllerStatus { | ||||
|     SticksValues stick_values{}; | ||||
|     ControllerMotionValues motion_values{}; | ||||
|     TriggerValues trigger_values{}; | ||||
|     ColorValues color_values{}; | ||||
|     BatteryValues battery_values{}; | ||||
|     VibrationValues vibration_values{}; | ||||
|     CameraValues camera_values{}; | ||||
|     RingAnalogValue ring_analog_value{}; | ||||
|     NfcValues nfc_values{}; | ||||
|  | ||||
|     // Data for HID services | ||||
|     HomeButtonState home_button_state{}; | ||||
|     CaptureButtonState capture_button_state{}; | ||||
|     NpadButtonState npad_button_state{}; | ||||
|     DebugPadButton debug_pad_button_state{}; | ||||
|     AnalogSticks analog_stick_state{}; | ||||
| @@ -159,6 +167,7 @@ enum class ControllerTriggerType { | ||||
|  | ||||
| struct ControllerUpdateCallback { | ||||
|     std::function<void(ControllerTriggerType)> on_change; | ||||
|     bool is_npad_service; | ||||
| }; | ||||
|  | ||||
| class EmulatedController { | ||||
| @@ -201,29 +210,43 @@ public: | ||||
|  | ||||
|     /** | ||||
|      * Sets the connected status to true | ||||
|      * @param use_temporary_value If true tmp_npad_type will be used | ||||
|      */ | ||||
|     void Connect(); | ||||
|     void Connect(bool use_temporary_value = false); | ||||
|  | ||||
|     /// Sets the connected status to false | ||||
|     void Disconnect(); | ||||
|  | ||||
|     /** | ||||
|      * Is the emulated connected | ||||
|      * @param get_temporary_value If true tmp_is_connected will be returned | ||||
|      * @return true if the controller has the connected status | ||||
|      */ | ||||
|     bool IsConnected() const; | ||||
|     bool IsConnected(bool get_temporary_value = false) const; | ||||
|  | ||||
|     /// Removes all callbacks created from input devices | ||||
|     void UnloadInput(); | ||||
|  | ||||
|     /** | ||||
|      * Sets the emulated controller into idle mode | ||||
|      * Sets the emulated controller into configuring mode | ||||
|      * This prevents the modification of the HID state of the emulated controller by input commands | ||||
|      */ | ||||
|     void DisableInput(); | ||||
|     void EnableConfiguration(); | ||||
|  | ||||
|     /// Returns the emulated controller into normal mode, allowing the modification of the HID state | ||||
|     void EnableInput(); | ||||
|     void DisableConfiguration(); | ||||
|  | ||||
|     /// Enables Home and Screenshot buttons | ||||
|     void EnableSystemButtons(); | ||||
|  | ||||
|     /// Disables Home and Screenshot buttons | ||||
|     void DisableSystemButtons(); | ||||
|  | ||||
|     /// Sets Home and Screenshot buttons to false | ||||
|     void ResetSystemButtons(); | ||||
|  | ||||
|     /// Returns true if the emulated controller is in configuring mode | ||||
|     bool IsConfiguring() const; | ||||
|  | ||||
|     /// Reload all input devices | ||||
|     void ReloadInput(); | ||||
| @@ -231,9 +254,75 @@ public: | ||||
|     /// Overrides current mapped devices with the stored configuration and reloads all input devices | ||||
|     void ReloadFromSettings(); | ||||
|  | ||||
|     /// Saves the current mapped configuration | ||||
|     void SaveCurrentConfig(); | ||||
|  | ||||
|     /// Reverts any mapped changes made that weren't saved | ||||
|     void RestoreConfig(); | ||||
|  | ||||
|     /// Returns a vector of mapped devices from the mapped button and stick parameters | ||||
|     std::vector<Common::ParamPackage> GetMappedDevices() const; | ||||
|  | ||||
|     // Returns the current mapped button device | ||||
|     Common::ParamPackage GetButtonParam(std::size_t index) const; | ||||
|  | ||||
|     // Returns the current mapped stick device | ||||
|     Common::ParamPackage GetStickParam(std::size_t index) const; | ||||
|  | ||||
|     // Returns the current mapped motion device | ||||
|     Common::ParamPackage GetMotionParam(std::size_t index) const; | ||||
|  | ||||
|     /** | ||||
|      * Updates the current mapped button device | ||||
|      * @param param ParamPackage with controller data to be mapped | ||||
|      */ | ||||
|     void SetButtonParam(std::size_t index, Common::ParamPackage param); | ||||
|  | ||||
|     /** | ||||
|      * Updates the current mapped stick device | ||||
|      * @param param ParamPackage with controller data to be mapped | ||||
|      */ | ||||
|     void SetStickParam(std::size_t index, Common::ParamPackage param); | ||||
|  | ||||
|     /** | ||||
|      * Updates the current mapped motion device | ||||
|      * @param param ParamPackage with controller data to be mapped | ||||
|      */ | ||||
|     void SetMotionParam(std::size_t index, Common::ParamPackage param); | ||||
|  | ||||
|     /// Auto calibrates the current motion devices | ||||
|     void StartMotionCalibration(); | ||||
|  | ||||
|     /// Returns the latest button status from the controller with parameters | ||||
|     ButtonValues GetButtonsValues() const; | ||||
|  | ||||
|     /// Returns the latest analog stick status from the controller with parameters | ||||
|     SticksValues GetSticksValues() const; | ||||
|  | ||||
|     /// Returns the latest trigger status from the controller with parameters | ||||
|     TriggerValues GetTriggersValues() const; | ||||
|  | ||||
|     /// Returns the latest motion status from the controller with parameters | ||||
|     ControllerMotionValues GetMotionValues() const; | ||||
|  | ||||
|     /// Returns the latest color status from the controller with parameters | ||||
|     ColorValues GetColorsValues() const; | ||||
|  | ||||
|     /// Returns the latest battery status from the controller with parameters | ||||
|     BatteryValues GetBatteryValues() const; | ||||
|  | ||||
|     /// Returns the latest camera status from the controller with parameters | ||||
|     CameraValues GetCameraValues() const; | ||||
|  | ||||
|     /// Returns the latest status of analog input from the ring sensor with parameters | ||||
|     RingAnalogValue GetRingSensorValues() const; | ||||
|  | ||||
|     /// Returns the latest status of button input for the hid::HomeButton service | ||||
|     HomeButtonState GetHomeButtons() const; | ||||
|  | ||||
|     /// Returns the latest status of button input for the hid::CaptureButton service | ||||
|     CaptureButtonState GetCaptureButtons() const; | ||||
|  | ||||
|     /// Returns the latest status of button input for the hid::Npad service | ||||
|     NpadButtonState GetNpadButtons() const; | ||||
|  | ||||
| @@ -343,15 +432,17 @@ private: | ||||
|     void LoadVirtualGamepadParams(); | ||||
|  | ||||
|     /** | ||||
|      * @param use_temporary_value If true tmp_npad_type will be used | ||||
|      * @return true if the controller style is fullkey | ||||
|      */ | ||||
|     bool IsControllerFullkey() const; | ||||
|     bool IsControllerFullkey(bool use_temporary_value = false) const; | ||||
|  | ||||
|     /** | ||||
|      * Checks the current controller type against the supported_style_tag | ||||
|      * @param use_temporary_value If true tmp_npad_type will be used | ||||
|      * @return true if the controller is supported | ||||
|      */ | ||||
|     bool IsControllerSupported() const; | ||||
|     bool IsControllerSupported(bool use_temporary_value = false) const; | ||||
|  | ||||
|     /** | ||||
|      * Updates the button status of the controller | ||||
| @@ -426,8 +517,9 @@ private: | ||||
|     /** | ||||
|      * Triggers a callback that something has changed on the controller status | ||||
|      * @param type Input type of the event to trigger | ||||
|      * @param is_service_update indicates if this event should only be sent to HID services | ||||
|      */ | ||||
|     void TriggerOnChange(ControllerTriggerType type); | ||||
|     void TriggerOnChange(ControllerTriggerType type, bool is_service_update); | ||||
|  | ||||
|     NpadButton GetTurboButtonMask() const; | ||||
|  | ||||
| @@ -436,10 +528,15 @@ private: | ||||
|     NpadStyleIndex original_npad_type{NpadStyleIndex::None}; | ||||
|     NpadStyleTag supported_style_tag{NpadStyleSet::All}; | ||||
|     bool is_connected{false}; | ||||
|     bool npad_input_enabled{true}; | ||||
|     bool is_configuring{false}; | ||||
|     bool system_buttons_enabled{true}; | ||||
|     f32 motion_sensitivity{Core::HID::MotionInput::IsAtRestStandard}; | ||||
|     u32 turbo_button_state{0}; | ||||
|  | ||||
|     // Temporary values to avoid doing changes while the controller is in configuring mode | ||||
|     NpadStyleIndex tmp_npad_type{NpadStyleIndex::None}; | ||||
|     bool tmp_is_connected{false}; | ||||
|  | ||||
|     ButtonParams button_params; | ||||
|     StickParams stick_params; | ||||
|     ControllerMotionParams motion_params; | ||||
|   | ||||
| @@ -6,7 +6,6 @@ | ||||
| #include "core/hid/emulated_controller.h" | ||||
| #include "core/hid/emulated_devices.h" | ||||
| #include "core/hid/hid_core.h" | ||||
| #include "core/hid/system_controller.h" | ||||
|  | ||||
| namespace Core::HID { | ||||
|  | ||||
| @@ -21,16 +20,6 @@ HIDCore::HIDCore() | ||||
|       player_8{std::make_unique<EmulatedController>(NpadIdType::Player8)}, | ||||
|       other{std::make_unique<EmulatedController>(NpadIdType::Other)}, | ||||
|       handheld{std::make_unique<EmulatedController>(NpadIdType::Handheld)}, | ||||
|       system_player_1{std::make_unique<SystemController>(NpadIdType::Player1)}, | ||||
|       system_player_2{std::make_unique<SystemController>(NpadIdType::Player2)}, | ||||
|       system_player_3{std::make_unique<SystemController>(NpadIdType::Player3)}, | ||||
|       system_player_4{std::make_unique<SystemController>(NpadIdType::Player4)}, | ||||
|       system_player_5{std::make_unique<SystemController>(NpadIdType::Player5)}, | ||||
|       system_player_6{std::make_unique<SystemController>(NpadIdType::Player6)}, | ||||
|       system_player_7{std::make_unique<SystemController>(NpadIdType::Player7)}, | ||||
|       system_player_8{std::make_unique<SystemController>(NpadIdType::Player8)}, | ||||
|       system_other{std::make_unique<SystemController>(NpadIdType::Other)}, | ||||
|       system_handheld{std::make_unique<SystemController>(NpadIdType::Handheld)}, | ||||
|       console{std::make_unique<EmulatedConsole>()}, devices{std::make_unique<EmulatedDevices>()} {} | ||||
|  | ||||
| HIDCore::~HIDCore() = default; | ||||
| @@ -92,65 +81,6 @@ const EmulatedController* HIDCore::GetEmulatedController(NpadIdType npad_id_type | ||||
|         return nullptr; | ||||
|     } | ||||
| } | ||||
|  | ||||
| SystemController* HIDCore::GetSystemController(NpadIdType npad_id_type) { | ||||
|     switch (npad_id_type) { | ||||
|     case NpadIdType::Player1: | ||||
|         return system_player_1.get(); | ||||
|     case NpadIdType::Player2: | ||||
|         return system_player_2.get(); | ||||
|     case NpadIdType::Player3: | ||||
|         return system_player_3.get(); | ||||
|     case NpadIdType::Player4: | ||||
|         return system_player_4.get(); | ||||
|     case NpadIdType::Player5: | ||||
|         return system_player_5.get(); | ||||
|     case NpadIdType::Player6: | ||||
|         return system_player_6.get(); | ||||
|     case NpadIdType::Player7: | ||||
|         return system_player_7.get(); | ||||
|     case NpadIdType::Player8: | ||||
|         return system_player_8.get(); | ||||
|     case NpadIdType::Other: | ||||
|         return system_other.get(); | ||||
|     case NpadIdType::Handheld: | ||||
|         return system_handheld.get(); | ||||
|     case NpadIdType::Invalid: | ||||
|     default: | ||||
|         ASSERT_MSG(false, "Invalid NpadIdType={}", npad_id_type); | ||||
|         return nullptr; | ||||
|     } | ||||
| } | ||||
|  | ||||
| const SystemController* HIDCore::GetSystemController(NpadIdType npad_id_type) const { | ||||
|     switch (npad_id_type) { | ||||
|     case NpadIdType::Player1: | ||||
|         return system_player_1.get(); | ||||
|     case NpadIdType::Player2: | ||||
|         return system_player_2.get(); | ||||
|     case NpadIdType::Player3: | ||||
|         return system_player_3.get(); | ||||
|     case NpadIdType::Player4: | ||||
|         return system_player_4.get(); | ||||
|     case NpadIdType::Player5: | ||||
|         return system_player_5.get(); | ||||
|     case NpadIdType::Player6: | ||||
|         return system_player_6.get(); | ||||
|     case NpadIdType::Player7: | ||||
|         return system_player_7.get(); | ||||
|     case NpadIdType::Player8: | ||||
|         return system_player_8.get(); | ||||
|     case NpadIdType::Other: | ||||
|         return system_other.get(); | ||||
|     case NpadIdType::Handheld: | ||||
|         return system_handheld.get(); | ||||
|     case NpadIdType::Invalid: | ||||
|     default: | ||||
|         ASSERT_MSG(false, "Invalid NpadIdType={}", npad_id_type); | ||||
|         return nullptr; | ||||
|     } | ||||
| } | ||||
|  | ||||
| EmulatedConsole* HIDCore::GetEmulatedConsole() { | ||||
|     return console.get(); | ||||
| } | ||||
| @@ -177,16 +107,16 @@ const EmulatedController* HIDCore::GetEmulatedControllerByIndex(std::size_t inde | ||||
|  | ||||
| void HIDCore::SetSupportedStyleTag(NpadStyleTag style_tag) { | ||||
|     supported_style_tag.raw = style_tag.raw; | ||||
|     system_player_1->SetSupportedNpadStyleTag(supported_style_tag); | ||||
|     system_player_2->SetSupportedNpadStyleTag(supported_style_tag); | ||||
|     system_player_3->SetSupportedNpadStyleTag(supported_style_tag); | ||||
|     system_player_4->SetSupportedNpadStyleTag(supported_style_tag); | ||||
|     system_player_5->SetSupportedNpadStyleTag(supported_style_tag); | ||||
|     system_player_6->SetSupportedNpadStyleTag(supported_style_tag); | ||||
|     system_player_7->SetSupportedNpadStyleTag(supported_style_tag); | ||||
|     system_player_8->SetSupportedNpadStyleTag(supported_style_tag); | ||||
|     system_other->SetSupportedNpadStyleTag(supported_style_tag); | ||||
|     system_handheld->SetSupportedNpadStyleTag(supported_style_tag); | ||||
|     player_1->SetSupportedNpadStyleTag(supported_style_tag); | ||||
|     player_2->SetSupportedNpadStyleTag(supported_style_tag); | ||||
|     player_3->SetSupportedNpadStyleTag(supported_style_tag); | ||||
|     player_4->SetSupportedNpadStyleTag(supported_style_tag); | ||||
|     player_5->SetSupportedNpadStyleTag(supported_style_tag); | ||||
|     player_6->SetSupportedNpadStyleTag(supported_style_tag); | ||||
|     player_7->SetSupportedNpadStyleTag(supported_style_tag); | ||||
|     player_8->SetSupportedNpadStyleTag(supported_style_tag); | ||||
|     other->SetSupportedNpadStyleTag(supported_style_tag); | ||||
|     handheld->SetSupportedNpadStyleTag(supported_style_tag); | ||||
| } | ||||
|  | ||||
| NpadStyleTag HIDCore::GetSupportedStyleTag() const { | ||||
| @@ -225,57 +155,57 @@ NpadIdType HIDCore::GetFirstDisconnectedNpadId() const { | ||||
| } | ||||
|  | ||||
| void HIDCore::EnableAllControllerConfiguration() { | ||||
|     system_player_1->EnableConfiguration(); | ||||
|     system_player_2->EnableConfiguration(); | ||||
|     system_player_3->EnableConfiguration(); | ||||
|     system_player_4->EnableConfiguration(); | ||||
|     system_player_5->EnableConfiguration(); | ||||
|     system_player_6->EnableConfiguration(); | ||||
|     system_player_7->EnableConfiguration(); | ||||
|     system_player_8->EnableConfiguration(); | ||||
|     system_other->EnableConfiguration(); | ||||
|     system_handheld->EnableConfiguration(); | ||||
|     player_1->EnableConfiguration(); | ||||
|     player_2->EnableConfiguration(); | ||||
|     player_3->EnableConfiguration(); | ||||
|     player_4->EnableConfiguration(); | ||||
|     player_5->EnableConfiguration(); | ||||
|     player_6->EnableConfiguration(); | ||||
|     player_7->EnableConfiguration(); | ||||
|     player_8->EnableConfiguration(); | ||||
|     other->EnableConfiguration(); | ||||
|     handheld->EnableConfiguration(); | ||||
| } | ||||
|  | ||||
| void HIDCore::DisableAllControllerConfiguration() { | ||||
|     system_player_1->DisableConfiguration(); | ||||
|     system_player_2->DisableConfiguration(); | ||||
|     system_player_3->DisableConfiguration(); | ||||
|     system_player_4->DisableConfiguration(); | ||||
|     system_player_5->DisableConfiguration(); | ||||
|     system_player_6->DisableConfiguration(); | ||||
|     system_player_7->DisableConfiguration(); | ||||
|     system_player_8->DisableConfiguration(); | ||||
|     system_other->DisableConfiguration(); | ||||
|     system_handheld->DisableConfiguration(); | ||||
|     player_1->DisableConfiguration(); | ||||
|     player_2->DisableConfiguration(); | ||||
|     player_3->DisableConfiguration(); | ||||
|     player_4->DisableConfiguration(); | ||||
|     player_5->DisableConfiguration(); | ||||
|     player_6->DisableConfiguration(); | ||||
|     player_7->DisableConfiguration(); | ||||
|     player_8->DisableConfiguration(); | ||||
|     other->DisableConfiguration(); | ||||
|     handheld->DisableConfiguration(); | ||||
| } | ||||
|  | ||||
| void HIDCore::ReloadInputDevices() { | ||||
|     system_player_1->ReloadFromSettings(); | ||||
|     system_player_2->ReloadFromSettings(); | ||||
|     system_player_3->ReloadFromSettings(); | ||||
|     system_player_4->ReloadFromSettings(); | ||||
|     system_player_5->ReloadFromSettings(); | ||||
|     system_player_6->ReloadFromSettings(); | ||||
|     system_player_7->ReloadFromSettings(); | ||||
|     system_player_8->ReloadFromSettings(); | ||||
|     system_other->ReloadFromSettings(); | ||||
|     system_handheld->ReloadFromSettings(); | ||||
|     player_1->ReloadFromSettings(); | ||||
|     player_2->ReloadFromSettings(); | ||||
|     player_3->ReloadFromSettings(); | ||||
|     player_4->ReloadFromSettings(); | ||||
|     player_5->ReloadFromSettings(); | ||||
|     player_6->ReloadFromSettings(); | ||||
|     player_7->ReloadFromSettings(); | ||||
|     player_8->ReloadFromSettings(); | ||||
|     other->ReloadFromSettings(); | ||||
|     handheld->ReloadFromSettings(); | ||||
|     console->ReloadFromSettings(); | ||||
|     devices->ReloadFromSettings(); | ||||
| } | ||||
|  | ||||
| void HIDCore::UnloadInputDevices() { | ||||
|     system_player_1->UnloadInput(); | ||||
|     system_player_2->UnloadInput(); | ||||
|     system_player_3->UnloadInput(); | ||||
|     system_player_4->UnloadInput(); | ||||
|     system_player_5->UnloadInput(); | ||||
|     system_player_6->UnloadInput(); | ||||
|     system_player_7->UnloadInput(); | ||||
|     system_player_8->UnloadInput(); | ||||
|     system_other->UnloadInput(); | ||||
|     system_handheld->UnloadInput(); | ||||
|     player_1->UnloadInput(); | ||||
|     player_2->UnloadInput(); | ||||
|     player_3->UnloadInput(); | ||||
|     player_4->UnloadInput(); | ||||
|     player_5->UnloadInput(); | ||||
|     player_6->UnloadInput(); | ||||
|     player_7->UnloadInput(); | ||||
|     player_8->UnloadInput(); | ||||
|     other->UnloadInput(); | ||||
|     handheld->UnloadInput(); | ||||
|     console->UnloadInput(); | ||||
|     devices->UnloadInput(); | ||||
| } | ||||
|   | ||||
| @@ -12,7 +12,6 @@ namespace Core::HID { | ||||
| class EmulatedConsole; | ||||
| class EmulatedController; | ||||
| class EmulatedDevices; | ||||
| class SystemController; | ||||
| } // namespace Core::HID | ||||
|  | ||||
| namespace Core::HID { | ||||
| @@ -31,12 +30,6 @@ public: | ||||
|     EmulatedController* GetEmulatedControllerByIndex(std::size_t index); | ||||
|     const EmulatedController* GetEmulatedControllerByIndex(std::size_t index) const; | ||||
|  | ||||
|     SystemController* GetSystemController(NpadIdType npad_id_type); | ||||
|     const SystemController* GetSystemController(NpadIdType npad_id_type) const; | ||||
|  | ||||
|     SystemController* GetSystemControllerByIndex(std::size_t index); | ||||
|     const SystemController* GetSystemControllerByIndex(std::size_t index) const; | ||||
|  | ||||
|     EmulatedConsole* GetEmulatedConsole(); | ||||
|     const EmulatedConsole* GetEmulatedConsole() const; | ||||
|  | ||||
| @@ -83,16 +76,6 @@ private: | ||||
|     std::unique_ptr<EmulatedController> handheld; | ||||
|     std::unique_ptr<EmulatedConsole> console; | ||||
|     std::unique_ptr<EmulatedDevices> devices; | ||||
|     std::unique_ptr<SystemController> system_player_1; | ||||
|     std::unique_ptr<SystemController> system_player_2; | ||||
|     std::unique_ptr<SystemController> system_player_3; | ||||
|     std::unique_ptr<SystemController> system_player_4; | ||||
|     std::unique_ptr<SystemController> system_player_5; | ||||
|     std::unique_ptr<SystemController> system_player_6; | ||||
|     std::unique_ptr<SystemController> system_player_7; | ||||
|     std::unique_ptr<SystemController> system_player_8; | ||||
|     std::unique_ptr<SystemController> system_other; | ||||
|     std::unique_ptr<SystemController> system_handheld; | ||||
|     NpadStyleTag supported_style_tag{NpadStyleSet::All}; | ||||
| }; | ||||
|  | ||||
|   | ||||
| @@ -1,860 +0,0 @@ | ||||
| // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later | ||||
|  | ||||
| #include <algorithm> | ||||
| #include <common/scope_exit.h> | ||||
|  | ||||
| #include "common/polyfill_ranges.h" | ||||
| #include "common/thread.h" | ||||
| #include "core/hid/system_controller.h" | ||||
| #include "core/hid/input_converter.h" | ||||
|  | ||||
| namespace Core::HID { | ||||
| constexpr s32 HID_JOYSTICK_MAX = 0x7fff; | ||||
| constexpr s32 HID_TRIGGER_MAX = 0x7fff; | ||||
|  | ||||
| SystemController::SystemController(NpadIdType npad_id_type_) : npad_id_type(npad_id_type_) {} | ||||
|  | ||||
| SystemController::~SystemController() = default; | ||||
|  | ||||
| NpadStyleIndex SystemController::MapSettingsTypeToNPad(Settings::ControllerType type) { | ||||
|     switch (type) { | ||||
|     case Settings::ControllerType::ProController: | ||||
|         return NpadStyleIndex::ProController; | ||||
|     case Settings::ControllerType::DualJoyconDetached: | ||||
|         return NpadStyleIndex::JoyconDual; | ||||
|     case Settings::ControllerType::LeftJoycon: | ||||
|         return NpadStyleIndex::JoyconLeft; | ||||
|     case Settings::ControllerType::RightJoycon: | ||||
|         return NpadStyleIndex::JoyconRight; | ||||
|     case Settings::ControllerType::Handheld: | ||||
|         return NpadStyleIndex::Handheld; | ||||
|     case Settings::ControllerType::GameCube: | ||||
|         return NpadStyleIndex::GameCube; | ||||
|     case Settings::ControllerType::Pokeball: | ||||
|         return NpadStyleIndex::Pokeball; | ||||
|     case Settings::ControllerType::NES: | ||||
|         return NpadStyleIndex::NES; | ||||
|     case Settings::ControllerType::SNES: | ||||
|         return NpadStyleIndex::SNES; | ||||
|     case Settings::ControllerType::N64: | ||||
|         return NpadStyleIndex::N64; | ||||
|     case Settings::ControllerType::SegaGenesis: | ||||
|         return NpadStyleIndex::SegaGenesis; | ||||
|     default: | ||||
|         return NpadStyleIndex::ProController; | ||||
|     } | ||||
| } | ||||
|  | ||||
| Settings::ControllerType SystemController::MapNPadToSettingsType(NpadStyleIndex type) { | ||||
|     switch (type) { | ||||
|     case NpadStyleIndex::ProController: | ||||
|         return Settings::ControllerType::ProController; | ||||
|     case NpadStyleIndex::JoyconDual: | ||||
|         return Settings::ControllerType::DualJoyconDetached; | ||||
|     case NpadStyleIndex::JoyconLeft: | ||||
|         return Settings::ControllerType::LeftJoycon; | ||||
|     case NpadStyleIndex::JoyconRight: | ||||
|         return Settings::ControllerType::RightJoycon; | ||||
|     case NpadStyleIndex::Handheld: | ||||
|         return Settings::ControllerType::Handheld; | ||||
|     case NpadStyleIndex::GameCube: | ||||
|         return Settings::ControllerType::GameCube; | ||||
|     case NpadStyleIndex::Pokeball: | ||||
|         return Settings::ControllerType::Pokeball; | ||||
|     case NpadStyleIndex::NES: | ||||
|         return Settings::ControllerType::NES; | ||||
|     case NpadStyleIndex::SNES: | ||||
|         return Settings::ControllerType::SNES; | ||||
|     case NpadStyleIndex::N64: | ||||
|         return Settings::ControllerType::N64; | ||||
|     case NpadStyleIndex::SegaGenesis: | ||||
|         return Settings::ControllerType::SegaGenesis; | ||||
|     default: | ||||
|         return Settings::ControllerType::ProController; | ||||
|     } | ||||
| } | ||||
|  | ||||
| void SystemController::ReloadFromSettings() { | ||||
|     const auto player_index = NpadIdTypeToIndex(npad_id_type); | ||||
|     const auto& player = Settings::values.players.GetValue()[player_index]; | ||||
|  | ||||
|     for (std::size_t index = 0; index < player.buttons.size(); ++index) { | ||||
|         button_params[index] = Common::ParamPackage(player.buttons[index]); | ||||
|     } | ||||
|     for (std::size_t index = 0; index < player.analogs.size(); ++index) { | ||||
|         stick_params[index] = Common::ParamPackage(player.analogs[index]); | ||||
|     } | ||||
|     for (std::size_t index = 0; index < player.motions.size(); ++index) { | ||||
|         motion_params[index] = Common::ParamPackage(player.motions[index]); | ||||
|     } | ||||
|  | ||||
|     ring_params[0] = Common::ParamPackage(Settings::values.ringcon_analogs); | ||||
|  | ||||
|     // Other or debug controller should always be a pro controller | ||||
|     if (npad_id_type != NpadIdType::Other) { | ||||
|         SetNpadStyleIndex(MapSettingsTypeToNPad(player.controller_type)); | ||||
|         original_npad_type = npad_type; | ||||
|     } else { | ||||
|         SetNpadStyleIndex(NpadStyleIndex::ProController); | ||||
|         original_npad_type = npad_type; | ||||
|     } | ||||
|  | ||||
|     Disconnect(); | ||||
|     if (player.connected) { | ||||
|         Connect(); | ||||
|     } | ||||
|  | ||||
|     ReloadInput(); | ||||
| } | ||||
|  | ||||
| void SystemController::LoadDevices() { | ||||
|     // TODO(german77): Use more buttons to detect the correct device | ||||
|     const auto left_joycon = button_params[Settings::NativeButton::DRight]; | ||||
|     const auto right_joycon = button_params[Settings::NativeButton::A]; | ||||
|  | ||||
|     // Triggers for GC controllers | ||||
|     trigger_params[LeftIndex] = button_params[Settings::NativeButton::ZL]; | ||||
|     trigger_params[RightIndex] = button_params[Settings::NativeButton::ZR]; | ||||
|  | ||||
|     std::ranges::transform(button_params, button_devices.begin(), Common::Input::CreateInputDevice); | ||||
|     std::ranges::transform(stick_params, stick_devices.begin(), Common::Input::CreateInputDevice); | ||||
|     std::ranges::transform(motion_params, motion_devices.begin(), Common::Input::CreateInputDevice); | ||||
|     std::ranges::transform(trigger_params, trigger_devices.begin(), | ||||
|                            Common::Input::CreateInputDevice); | ||||
| } | ||||
|  | ||||
| void SystemController::ReloadInput() { | ||||
|     // If you load any device here add the equivalent to the UnloadInput() function | ||||
|     LoadDevices(); | ||||
|     for (std::size_t index = 0; index < button_devices.size(); ++index) { | ||||
|         if (!button_devices[index]) { | ||||
|             continue; | ||||
|         } | ||||
|         const auto uuid = Common::UUID{button_params[index].Get("guid", "")}; | ||||
|         button_devices[index]->SetCallback({ | ||||
|             .on_change = | ||||
|                 [this, index, uuid](const Common::Input::CallbackStatus& callback) { | ||||
|                     SetButton(callback, index, uuid); | ||||
|                 }, | ||||
|         }); | ||||
|         button_devices[index]->ForceUpdate(); | ||||
|     } | ||||
|  | ||||
|     for (std::size_t index = 0; index < stick_devices.size(); ++index) { | ||||
|         if (!stick_devices[index]) { | ||||
|             continue; | ||||
|         } | ||||
|         const auto uuid = Common::UUID{stick_params[index].Get("guid", "")}; | ||||
|         stick_devices[index]->SetCallback({ | ||||
|             .on_change = | ||||
|                 [this, index, uuid](const Common::Input::CallbackStatus& callback) { | ||||
|                     SetStick(callback, index, uuid); | ||||
|                 }, | ||||
|         }); | ||||
|         stick_devices[index]->ForceUpdate(); | ||||
|     } | ||||
|  | ||||
|     for (std::size_t index = 0; index < trigger_devices.size(); ++index) { | ||||
|         if (!trigger_devices[index]) { | ||||
|             continue; | ||||
|         } | ||||
|         const auto uuid = Common::UUID{trigger_params[index].Get("guid", "")}; | ||||
|         trigger_devices[index]->SetCallback({ | ||||
|             .on_change = | ||||
|                 [this, index, uuid](const Common::Input::CallbackStatus& callback) { | ||||
|                     SetTrigger(callback, index, uuid); | ||||
|                 }, | ||||
|         }); | ||||
|         trigger_devices[index]->ForceUpdate(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void SystemController::UnloadInput() { | ||||
|     for (auto& button : button_devices) { | ||||
|         button.reset(); | ||||
|     } | ||||
|     for (auto& stick : stick_devices) { | ||||
|         stick.reset(); | ||||
|     } | ||||
|     for (auto& motion : motion_devices) { | ||||
|         motion.reset(); | ||||
|     } | ||||
|     for (auto& trigger : trigger_devices) { | ||||
|         trigger.reset(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void SystemController::EnableConfiguration() { | ||||
|     is_configuring = true; | ||||
|     tmp_is_connected = is_connected; | ||||
|     tmp_npad_type = npad_type; | ||||
| } | ||||
|  | ||||
| void SystemController::DisableConfiguration() { | ||||
|     is_configuring = false; | ||||
|  | ||||
|     // Apply temporary npad type to the real controller | ||||
|     if (tmp_npad_type != npad_type) { | ||||
|         if (is_connected) { | ||||
|             Disconnect(); | ||||
|         } | ||||
|         SetNpadStyleIndex(tmp_npad_type); | ||||
|         original_npad_type = tmp_npad_type; | ||||
|     } | ||||
|  | ||||
|     // Apply temporary connected status to the real controller | ||||
|     if (tmp_is_connected != is_connected) { | ||||
|         if (tmp_is_connected) { | ||||
|             Connect(); | ||||
|             return; | ||||
|         } | ||||
|         Disconnect(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void SystemController::EnableSystemButtons() { | ||||
|     std::scoped_lock lock{mutex}; | ||||
|     system_buttons_enabled = true; | ||||
| } | ||||
|  | ||||
| void SystemController::DisableSystemButtons() { | ||||
|     std::scoped_lock lock{mutex}; | ||||
|     system_buttons_enabled = false; | ||||
|     controller.home_button_state.raw = 0; | ||||
|     controller.capture_button_state.raw = 0; | ||||
| } | ||||
|  | ||||
| void SystemController::ResetSystemButtons() { | ||||
|     std::scoped_lock lock{mutex}; | ||||
|     controller.home_button_state.home.Assign(false); | ||||
|     controller.capture_button_state.capture.Assign(false); | ||||
| } | ||||
|  | ||||
| bool SystemController::IsConfiguring() const { | ||||
|     return is_configuring; | ||||
| } | ||||
|  | ||||
| void SystemController::SaveCurrentConfig() { | ||||
|     const auto player_index = NpadIdTypeToIndex(npad_id_type); | ||||
|     auto& player = Settings::values.players.GetValue()[player_index]; | ||||
|     player.connected = is_connected; | ||||
|     player.controller_type = MapNPadToSettingsType(npad_type); | ||||
|     for (std::size_t index = 0; index < player.buttons.size(); ++index) { | ||||
|         player.buttons[index] = button_params[index].Serialize(); | ||||
|     } | ||||
|     for (std::size_t index = 0; index < player.analogs.size(); ++index) { | ||||
|         player.analogs[index] = stick_params[index].Serialize(); | ||||
|     } | ||||
|     for (std::size_t index = 0; index < player.motions.size(); ++index) { | ||||
|         player.motions[index] = motion_params[index].Serialize(); | ||||
|     } | ||||
|     if (npad_id_type == NpadIdType::Player1) { | ||||
|         Settings::values.ringcon_analogs = ring_params[0].Serialize(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void SystemController::RestoreConfig() { | ||||
|     if (!is_configuring) { | ||||
|         return; | ||||
|     } | ||||
|     ReloadFromSettings(); | ||||
| } | ||||
|  | ||||
| std::vector<Common::ParamPackage> SystemController::GetMappedDevices() const { | ||||
|     std::vector<Common::ParamPackage> devices; | ||||
|     for (const auto& param : button_params) { | ||||
|         if (!param.Has("engine")) { | ||||
|             continue; | ||||
|         } | ||||
|         const auto devices_it = std::find_if( | ||||
|             devices.begin(), devices.end(), [¶m](const Common::ParamPackage& param_) { | ||||
|                 return param.Get("engine", "") == param_.Get("engine", "") && | ||||
|                        param.Get("guid", "") == param_.Get("guid", "") && | ||||
|                        param.Get("port", 0) == param_.Get("port", 0) && | ||||
|                        param.Get("pad", 0) == param_.Get("pad", 0); | ||||
|             }); | ||||
|         if (devices_it != devices.end()) { | ||||
|             continue; | ||||
|         } | ||||
|  | ||||
|         auto& device = devices.emplace_back(); | ||||
|         device.Set("engine", param.Get("engine", "")); | ||||
|         device.Set("guid", param.Get("guid", "")); | ||||
|         device.Set("port", param.Get("port", 0)); | ||||
|         device.Set("pad", param.Get("pad", 0)); | ||||
|     } | ||||
|  | ||||
|     for (const auto& param : stick_params) { | ||||
|         if (!param.Has("engine")) { | ||||
|             continue; | ||||
|         } | ||||
|         if (param.Get("engine", "") == "analog_from_button") { | ||||
|             continue; | ||||
|         } | ||||
|         const auto devices_it = std::find_if( | ||||
|             devices.begin(), devices.end(), [¶m](const Common::ParamPackage& param_) { | ||||
|                 return param.Get("engine", "") == param_.Get("engine", "") && | ||||
|                        param.Get("guid", "") == param_.Get("guid", "") && | ||||
|                        param.Get("port", 0) == param_.Get("port", 0) && | ||||
|                        param.Get("pad", 0) == param_.Get("pad", 0); | ||||
|             }); | ||||
|         if (devices_it != devices.end()) { | ||||
|             continue; | ||||
|         } | ||||
|  | ||||
|         auto& device = devices.emplace_back(); | ||||
|         device.Set("engine", param.Get("engine", "")); | ||||
|         device.Set("guid", param.Get("guid", "")); | ||||
|         device.Set("port", param.Get("port", 0)); | ||||
|         device.Set("pad", param.Get("pad", 0)); | ||||
|     } | ||||
|     return devices; | ||||
| } | ||||
|  | ||||
| Common::ParamPackage SystemController::GetButtonParam(std::size_t index) const { | ||||
|     if (index >= button_params.size()) { | ||||
|         return {}; | ||||
|     } | ||||
|     return button_params[index]; | ||||
| } | ||||
|  | ||||
| Common::ParamPackage SystemController::GetStickParam(std::size_t index) const { | ||||
|     if (index >= stick_params.size()) { | ||||
|         return {}; | ||||
|     } | ||||
|     return stick_params[index]; | ||||
| } | ||||
|  | ||||
| Common::ParamPackage SystemController::GetMotionParam(std::size_t index) const { | ||||
|     if (index >= motion_params.size()) { | ||||
|         return {}; | ||||
|     } | ||||
|     return motion_params[index]; | ||||
| } | ||||
|  | ||||
| void SystemController::SetButtonParam(std::size_t index, Common::ParamPackage param) { | ||||
|     if (index >= button_params.size()) { | ||||
|         return; | ||||
|     } | ||||
|     button_params[index] = std::move(param); | ||||
|     ReloadInput(); | ||||
| } | ||||
|  | ||||
| void SystemController::SetStickParam(std::size_t index, Common::ParamPackage param) { | ||||
|     if (index >= stick_params.size()) { | ||||
|         return; | ||||
|     } | ||||
|     stick_params[index] = std::move(param); | ||||
|     ReloadInput(); | ||||
| } | ||||
|  | ||||
| void SystemController::SetMotionParam(std::size_t index, Common::ParamPackage param) { | ||||
|     if (index >= motion_params.size()) { | ||||
|         return; | ||||
|     } | ||||
|     motion_params[index] = std::move(param); | ||||
|     ReloadInput(); | ||||
| } | ||||
|  | ||||
| void SystemController::SetButton(const Common::Input::CallbackStatus& callback, std::size_t index, | ||||
|                                    Common::UUID uuid) { | ||||
|     if (index >= controller.button_values.size()) { | ||||
|         return; | ||||
|     } | ||||
|     std::unique_lock lock{mutex}; | ||||
|     bool value_changed = false; | ||||
|     const auto new_status = TransformToButton(callback); | ||||
|     auto& current_status = controller.button_values[index]; | ||||
|  | ||||
|     // Only read button values that have the same uuid or are pressed once | ||||
|     if (current_status.uuid != uuid) { | ||||
|         if (!new_status.value) { | ||||
|             return; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     current_status.toggle = new_status.toggle; | ||||
|     current_status.turbo = new_status.turbo; | ||||
|     current_status.uuid = uuid; | ||||
|  | ||||
|     // Update button status with current | ||||
|     if (!current_status.toggle) { | ||||
|         current_status.locked = false; | ||||
|         if (current_status.value != new_status.value) { | ||||
|             current_status.value = new_status.value; | ||||
|             value_changed = true; | ||||
|         } | ||||
|     } else { | ||||
|         // Toggle button and lock status | ||||
|         if (new_status.value && !current_status.locked) { | ||||
|             current_status.locked = true; | ||||
|             current_status.value = !current_status.value; | ||||
|             value_changed = true; | ||||
|         } | ||||
|  | ||||
|         // Unlock button ready for next press | ||||
|         if (!new_status.value && current_status.locked) { | ||||
|             current_status.locked = false; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     if (!value_changed) { | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     if (is_configuring) { | ||||
|         controller.npad_button_state.raw = NpadButton::None; | ||||
|         controller.home_button_state.raw = 0; | ||||
|         controller.capture_button_state.raw = 0; | ||||
|         lock.unlock(); | ||||
|         TriggerOnChange(ControllerTriggerType::Button, false); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     // GC controllers have triggers not buttons | ||||
|     if (npad_type == NpadStyleIndex::GameCube) { | ||||
|         if (index == Settings::NativeButton::ZR) { | ||||
|             return; | ||||
|         } | ||||
|         if (index == Settings::NativeButton::ZL) { | ||||
|             return; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     switch (index) { | ||||
|     case Settings::NativeButton::A: | ||||
|         controller.npad_button_state.a.Assign(current_status.value); | ||||
|         break; | ||||
|     case Settings::NativeButton::B: | ||||
|         controller.npad_button_state.b.Assign(current_status.value); | ||||
|         break; | ||||
|     case Settings::NativeButton::X: | ||||
|         controller.npad_button_state.x.Assign(current_status.value); | ||||
|         break; | ||||
|     case Settings::NativeButton::Y: | ||||
|         controller.npad_button_state.y.Assign(current_status.value); | ||||
|         break; | ||||
|     case Settings::NativeButton::LStick: | ||||
|         controller.npad_button_state.stick_l.Assign(current_status.value); | ||||
|         break; | ||||
|     case Settings::NativeButton::RStick: | ||||
|         controller.npad_button_state.stick_r.Assign(current_status.value); | ||||
|         break; | ||||
|     case Settings::NativeButton::L: | ||||
|         controller.npad_button_state.l.Assign(current_status.value); | ||||
|         break; | ||||
|     case Settings::NativeButton::R: | ||||
|         controller.npad_button_state.r.Assign(current_status.value); | ||||
|         break; | ||||
|     case Settings::NativeButton::ZL: | ||||
|         controller.npad_button_state.zl.Assign(current_status.value); | ||||
|         break; | ||||
|     case Settings::NativeButton::ZR: | ||||
|         controller.npad_button_state.zr.Assign(current_status.value); | ||||
|         break; | ||||
|     case Settings::NativeButton::Plus: | ||||
|         controller.npad_button_state.plus.Assign(current_status.value); | ||||
|         break; | ||||
|     case Settings::NativeButton::Minus: | ||||
|         controller.npad_button_state.minus.Assign(current_status.value); | ||||
|         break; | ||||
|     case Settings::NativeButton::DLeft: | ||||
|         controller.npad_button_state.left.Assign(current_status.value); | ||||
|         break; | ||||
|     case Settings::NativeButton::DUp: | ||||
|         controller.npad_button_state.up.Assign(current_status.value); | ||||
|         break; | ||||
|     case Settings::NativeButton::DRight: | ||||
|         controller.npad_button_state.right.Assign(current_status.value); | ||||
|         break; | ||||
|     case Settings::NativeButton::DDown: | ||||
|         controller.npad_button_state.down.Assign(current_status.value); | ||||
|         break; | ||||
|     case Settings::NativeButton::SL: | ||||
|         controller.npad_button_state.left_sl.Assign(current_status.value); | ||||
|         controller.npad_button_state.right_sl.Assign(current_status.value); | ||||
|         break; | ||||
|     case Settings::NativeButton::SR: | ||||
|         controller.npad_button_state.left_sr.Assign(current_status.value); | ||||
|         controller.npad_button_state.right_sr.Assign(current_status.value); | ||||
|         break; | ||||
|     case Settings::NativeButton::Home: | ||||
|         if (!system_buttons_enabled) { | ||||
|             break; | ||||
|         } | ||||
|         controller.home_button_state.home.Assign(current_status.value); | ||||
|         break; | ||||
|     case Settings::NativeButton::Screenshot: | ||||
|         if (!system_buttons_enabled) { | ||||
|             break; | ||||
|         } | ||||
|         controller.capture_button_state.capture.Assign(current_status.value); | ||||
|         break; | ||||
|     } | ||||
|  | ||||
|     lock.unlock(); | ||||
|  | ||||
|     if (!is_connected) { | ||||
|         if (npad_id_type == NpadIdType::Player1 && npad_type != NpadStyleIndex::Handheld) { | ||||
|             Connect(); | ||||
|         } | ||||
|         if (npad_id_type == NpadIdType::Handheld && npad_type == NpadStyleIndex::Handheld) { | ||||
|             Connect(); | ||||
|         } | ||||
|     } | ||||
|     TriggerOnChange(ControllerTriggerType::Button, true); | ||||
| } | ||||
|  | ||||
| void SystemController::SetStick(const Common::Input::CallbackStatus& callback, std::size_t index, | ||||
|                                   Common::UUID uuid) { | ||||
|     if (index >= controller.stick_values.size()) { | ||||
|         return; | ||||
|     } | ||||
|     auto trigger_guard = | ||||
|         SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Stick, !is_configuring); }); | ||||
|     std::scoped_lock lock{mutex}; | ||||
|     const auto stick_value = TransformToStick(callback); | ||||
|  | ||||
|     // Only read stick values that have the same uuid or are over the threshold to avoid flapping | ||||
|     if (controller.stick_values[index].uuid != uuid) { | ||||
|         if (!stick_value.down && !stick_value.up && !stick_value.left && | ||||
|             !stick_value.right) { | ||||
|             trigger_guard.Cancel(); | ||||
|             return; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     controller.stick_values[index] = stick_value; | ||||
|     controller.stick_values[index].uuid = uuid; | ||||
|  | ||||
|     if (is_configuring) { | ||||
|         controller.analog_stick_state.left = {}; | ||||
|         controller.analog_stick_state.right = {}; | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     const AnalogStickState stick{ | ||||
|         .x = static_cast<s32>(controller.stick_values[index].x.value * HID_JOYSTICK_MAX), | ||||
|         .y = static_cast<s32>(controller.stick_values[index].y.value * HID_JOYSTICK_MAX), | ||||
|     }; | ||||
|  | ||||
|     switch (index) { | ||||
|     case Settings::NativeAnalog::LStick: | ||||
|         controller.analog_stick_state.left = stick; | ||||
|         controller.npad_button_state.stick_l_left.Assign(controller.stick_values[index].left); | ||||
|         controller.npad_button_state.stick_l_up.Assign(controller.stick_values[index].up); | ||||
|         controller.npad_button_state.stick_l_right.Assign(controller.stick_values[index].right); | ||||
|         controller.npad_button_state.stick_l_down.Assign(controller.stick_values[index].down); | ||||
|         break; | ||||
|     case Settings::NativeAnalog::RStick: | ||||
|         controller.analog_stick_state.right = stick; | ||||
|         controller.npad_button_state.stick_r_left.Assign(controller.stick_values[index].left); | ||||
|         controller.npad_button_state.stick_r_up.Assign(controller.stick_values[index].up); | ||||
|         controller.npad_button_state.stick_r_right.Assign(controller.stick_values[index].right); | ||||
|         controller.npad_button_state.stick_r_down.Assign(controller.stick_values[index].down); | ||||
|         break; | ||||
|     } | ||||
| } | ||||
|  | ||||
| void SystemController::SetTrigger(const Common::Input::CallbackStatus& callback, | ||||
|                                     std::size_t index, Common::UUID uuid) { | ||||
|     if (index >= controller.trigger_values.size()) { | ||||
|         return; | ||||
|     } | ||||
|     auto trigger_guard = | ||||
|         SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Trigger, !is_configuring); }); | ||||
|     std::scoped_lock lock{mutex}; | ||||
|     const auto trigger_value = TransformToTrigger(callback); | ||||
|  | ||||
|     // Only read trigger values that have the same uuid or are pressed once | ||||
|     if (controller.trigger_values[index].uuid != uuid) { | ||||
|         if (!trigger_value.pressed.value) { | ||||
|             return; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     controller.trigger_values[index] = trigger_value; | ||||
|     controller.trigger_values[index].uuid = uuid; | ||||
|  | ||||
|     if (is_configuring) { | ||||
|         controller.gc_trigger_state.left = 0; | ||||
|         controller.gc_trigger_state.right = 0; | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     // Only GC controllers have analog triggers | ||||
|     if (npad_type != NpadStyleIndex::GameCube) { | ||||
|         trigger_guard.Cancel(); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     const auto& trigger = controller.trigger_values[index]; | ||||
|  | ||||
|     switch (index) { | ||||
|     case Settings::NativeTrigger::LTrigger: | ||||
|         controller.gc_trigger_state.left = static_cast<s32>(trigger.analog.value * HID_TRIGGER_MAX); | ||||
|         controller.npad_button_state.zl.Assign(trigger.pressed.value); | ||||
|         break; | ||||
|     case Settings::NativeTrigger::RTrigger: | ||||
|         controller.gc_trigger_state.right = | ||||
|             static_cast<s32>(trigger.analog.value * HID_TRIGGER_MAX); | ||||
|         controller.npad_button_state.zr.Assign(trigger.pressed.value); | ||||
|         break; | ||||
|     } | ||||
| } | ||||
|  | ||||
| void SystemController::SetSupportedNpadStyleTag(NpadStyleTag supported_styles) { | ||||
|     supported_style_tag = supported_styles; | ||||
|     if (!is_connected) { | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     // Attempt to reconnect with the original type | ||||
|     if (npad_type != original_npad_type) { | ||||
|         Disconnect(); | ||||
|         const auto current_npad_type = npad_type; | ||||
|         SetNpadStyleIndex(original_npad_type); | ||||
|         if (IsControllerSupported()) { | ||||
|             Connect(); | ||||
|             return; | ||||
|         } | ||||
|         SetNpadStyleIndex(current_npad_type); | ||||
|         Connect(); | ||||
|     } | ||||
|  | ||||
|     if (IsControllerSupported()) { | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     Disconnect(); | ||||
|  | ||||
|     // Fallback Fullkey controllers to Pro controllers | ||||
|     if (IsControllerFullkey() && supported_style_tag.fullkey) { | ||||
|         LOG_WARNING(Service_HID, "Reconnecting controller type {} as Pro controller", npad_type); | ||||
|         SetNpadStyleIndex(NpadStyleIndex::ProController); | ||||
|         Connect(); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     // Fallback Dual joycon controllers to Pro controllers | ||||
|     if (npad_type == NpadStyleIndex::JoyconDual && supported_style_tag.fullkey) { | ||||
|         LOG_WARNING(Service_HID, "Reconnecting controller type {} as Pro controller", npad_type); | ||||
|         SetNpadStyleIndex(NpadStyleIndex::ProController); | ||||
|         Connect(); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     // Fallback Pro controllers to Dual joycon | ||||
|     if (npad_type == NpadStyleIndex::ProController && supported_style_tag.joycon_dual) { | ||||
|         LOG_WARNING(Service_HID, "Reconnecting controller type {} as Dual Joycons", npad_type); | ||||
|         SetNpadStyleIndex(NpadStyleIndex::JoyconDual); | ||||
|         Connect(); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     LOG_ERROR(Service_HID, "Controller type {} is not supported. Disconnecting controller", | ||||
|               npad_type); | ||||
| } | ||||
|  | ||||
| bool SystemController::IsControllerFullkey(bool use_temporary_value) const { | ||||
|     std::scoped_lock lock{mutex}; | ||||
|     const auto type = is_configuring && use_temporary_value ? tmp_npad_type : npad_type; | ||||
|     switch (type) { | ||||
|     case NpadStyleIndex::ProController: | ||||
|     case NpadStyleIndex::GameCube: | ||||
|     case NpadStyleIndex::NES: | ||||
|     case NpadStyleIndex::SNES: | ||||
|     case NpadStyleIndex::N64: | ||||
|     case NpadStyleIndex::SegaGenesis: | ||||
|         return true; | ||||
|     default: | ||||
|         return false; | ||||
|     } | ||||
| } | ||||
|  | ||||
| bool SystemController::IsControllerSupported(bool use_temporary_value) const { | ||||
|     std::scoped_lock lock{mutex}; | ||||
|     const auto type = is_configuring && use_temporary_value ? tmp_npad_type : npad_type; | ||||
|     switch (type) { | ||||
|     case NpadStyleIndex::ProController: | ||||
|         return supported_style_tag.fullkey.As<bool>(); | ||||
|     case NpadStyleIndex::Handheld: | ||||
|         return supported_style_tag.handheld.As<bool>(); | ||||
|     case NpadStyleIndex::JoyconDual: | ||||
|         return supported_style_tag.joycon_dual.As<bool>(); | ||||
|     case NpadStyleIndex::JoyconLeft: | ||||
|         return supported_style_tag.joycon_left.As<bool>(); | ||||
|     case NpadStyleIndex::JoyconRight: | ||||
|         return supported_style_tag.joycon_right.As<bool>(); | ||||
|     case NpadStyleIndex::GameCube: | ||||
|         return supported_style_tag.gamecube.As<bool>(); | ||||
|     case NpadStyleIndex::Pokeball: | ||||
|         return supported_style_tag.palma.As<bool>(); | ||||
|     case NpadStyleIndex::NES: | ||||
|         return supported_style_tag.lark.As<bool>(); | ||||
|     case NpadStyleIndex::SNES: | ||||
|         return supported_style_tag.lucia.As<bool>(); | ||||
|     case NpadStyleIndex::N64: | ||||
|         return supported_style_tag.lagoon.As<bool>(); | ||||
|     case NpadStyleIndex::SegaGenesis: | ||||
|         return supported_style_tag.lager.As<bool>(); | ||||
|     default: | ||||
|         return false; | ||||
|     } | ||||
| } | ||||
|  | ||||
| void SystemController::Connect(bool use_temporary_value) { | ||||
|     if (!IsControllerSupported(use_temporary_value)) { | ||||
|         const auto type = is_configuring && use_temporary_value ? tmp_npad_type : npad_type; | ||||
|         LOG_ERROR(Service_HID, "Controller type {} is not supported", type); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     auto trigger_guard = | ||||
|         SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Connected, !is_configuring); }); | ||||
|     std::scoped_lock lock{mutex}; | ||||
|     if (is_configuring) { | ||||
|         tmp_is_connected = true; | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     if (is_connected) { | ||||
|         trigger_guard.Cancel(); | ||||
|         return; | ||||
|     } | ||||
|     is_connected = true; | ||||
| } | ||||
|  | ||||
| void SystemController::Disconnect() { | ||||
|     auto trigger_guard = | ||||
|         SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Disconnected, !is_configuring); }); | ||||
|     std::scoped_lock lock{mutex}; | ||||
|     if (is_configuring) { | ||||
|         tmp_is_connected = false; | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     if (!is_connected) { | ||||
|         trigger_guard.Cancel(); | ||||
|         return; | ||||
|     } | ||||
|     is_connected = false; | ||||
| } | ||||
|  | ||||
| bool SystemController::IsConnected(bool get_temporary_value) const { | ||||
|     std::scoped_lock lock{mutex}; | ||||
|     if (get_temporary_value && is_configuring) { | ||||
|         return tmp_is_connected; | ||||
|     } | ||||
|     return is_connected; | ||||
| } | ||||
|  | ||||
| NpadIdType SystemController::GetNpadIdType() const { | ||||
|     std::scoped_lock lock{mutex}; | ||||
|     return npad_id_type; | ||||
| } | ||||
|  | ||||
| NpadStyleIndex SystemController::GetNpadStyleIndex(bool get_temporary_value) const { | ||||
|     std::scoped_lock lock{mutex}; | ||||
|     if (get_temporary_value && is_configuring) { | ||||
|         return tmp_npad_type; | ||||
|     } | ||||
|     return npad_type; | ||||
| } | ||||
|  | ||||
| void SystemController::SetNpadStyleIndex(NpadStyleIndex npad_type_) { | ||||
|     auto trigger_guard = | ||||
|         SCOPE_GUARD({ TriggerOnChange(ControllerTriggerType::Type, !is_configuring); }); | ||||
|     std::scoped_lock lock{mutex}; | ||||
|  | ||||
|     if (is_configuring) { | ||||
|         if (tmp_npad_type == npad_type_) { | ||||
|             trigger_guard.Cancel(); | ||||
|             return; | ||||
|         } | ||||
|         tmp_npad_type = npad_type_; | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     if (npad_type == npad_type_) { | ||||
|         trigger_guard.Cancel(); | ||||
|         return; | ||||
|     } | ||||
|     if (is_connected) { | ||||
|         LOG_WARNING(Service_HID, "Controller {} type changed while it's connected", | ||||
|                     NpadIdTypeToIndex(npad_id_type)); | ||||
|     } | ||||
|     npad_type = npad_type_; | ||||
| } | ||||
|  | ||||
| ButtonValues SystemController::GetButtonsValues() const { | ||||
|     std::scoped_lock lock{mutex}; | ||||
|     return controller.button_values; | ||||
| } | ||||
|  | ||||
| SticksValues SystemController::GetSticksValues() const { | ||||
|     std::scoped_lock lock{mutex}; | ||||
|     return controller.stick_values; | ||||
| } | ||||
|  | ||||
| TriggerValues SystemController::GetTriggersValues() const { | ||||
|     std::scoped_lock lock{mutex}; | ||||
|     return controller.trigger_values; | ||||
| } | ||||
|  | ||||
| HomeButtonState SystemController::GetHomeButtons() const { | ||||
|     std::scoped_lock lock{mutex}; | ||||
|     return controller.home_button_state; | ||||
| } | ||||
|  | ||||
| CaptureButtonState SystemController::GetCaptureButtons() const { | ||||
|     std::scoped_lock lock{mutex}; | ||||
|     return controller.capture_button_state; | ||||
| } | ||||
|  | ||||
| NpadButtonState SystemController::GetNpadButtons() const { | ||||
|     std::scoped_lock lock{mutex}; | ||||
|     return controller.npad_button_state; | ||||
| } | ||||
|  | ||||
| AnalogSticks SystemController::GetSticks() const { | ||||
|     std::scoped_lock lock{mutex}; | ||||
|     return controller.analog_stick_state; | ||||
| } | ||||
|  | ||||
| NpadGcTriggerState SystemController::GetTriggers() const { | ||||
|     std::scoped_lock lock{mutex}; | ||||
|     return controller.gc_trigger_state; | ||||
| } | ||||
|  | ||||
| void SystemController::TriggerOnChange(ControllerTriggerType type, bool is_npad_service_update) { | ||||
|     std::scoped_lock lock{callback_mutex}; | ||||
|     for (const auto& poller_pair : callback_list) { | ||||
|         const ControllerUpdateCallback& poller = poller_pair.second; | ||||
|         if (!is_npad_service_update && poller.is_npad_service) { | ||||
|             continue; | ||||
|         } | ||||
|         if (poller.on_change) { | ||||
|             poller.on_change(type); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| int SystemController::SetCallback(ControllerUpdateCallback update_callback) { | ||||
|     std::scoped_lock lock{callback_mutex}; | ||||
|     callback_list.insert_or_assign(last_callback_key, std::move(update_callback)); | ||||
|     return last_callback_key++; | ||||
| } | ||||
|  | ||||
| void SystemController::DeleteCallback(int key) { | ||||
|     std::scoped_lock lock{callback_mutex}; | ||||
|     const auto& iterator = callback_list.find(key); | ||||
|     if (iterator == callback_list.end()) { | ||||
|         LOG_ERROR(Input, "Tried to delete non-existent callback {}", key); | ||||
|         return; | ||||
|     } | ||||
|     callback_list.erase(iterator); | ||||
| } | ||||
|  | ||||
| } // namespace Core::HID | ||||
| @@ -1,330 +0,0 @@ | ||||
| // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include <array> | ||||
| #include <functional> | ||||
| #include <memory> | ||||
| #include <mutex> | ||||
| #include <unordered_map> | ||||
| #include <vector> | ||||
|  | ||||
| #include "common/common_types.h" | ||||
| #include "common/input.h" | ||||
| #include "common/param_package.h" | ||||
| #include "common/settings.h" | ||||
| #include "common/vector_math.h" | ||||
| #include "core/hid/hid_types.h" | ||||
| #include "core/hid/irs_types.h" | ||||
| #include "core/hid/motion_input.h" | ||||
|  | ||||
| namespace Core::HID { | ||||
| const std::size_t max_emulated_controllers = 2; | ||||
| const std::size_t output_devices_size = 4; | ||||
| struct ControllerMotionInfo { | ||||
|     Common::Input::MotionStatus raw_status{}; | ||||
|     MotionInput emulated{}; | ||||
| }; | ||||
|  | ||||
| using ButtonDevices = | ||||
|     std::array<std::unique_ptr<Common::Input::InputDevice>, Settings::NativeButton::NumButtons>; | ||||
| using StickDevices = | ||||
|     std::array<std::unique_ptr<Common::Input::InputDevice>, Settings::NativeAnalog::NumAnalogs>; | ||||
| using ControllerMotionDevices = | ||||
|     std::array<std::unique_ptr<Common::Input::InputDevice>, Settings::NativeMotion::NumMotions>; | ||||
| using TriggerDevices = | ||||
|     std::array<std::unique_ptr<Common::Input::InputDevice>, Settings::NativeTrigger::NumTriggers>; | ||||
|  | ||||
| using ButtonParams = std::array<Common::ParamPackage, Settings::NativeButton::NumButtons>; | ||||
| using StickParams = std::array<Common::ParamPackage, Settings::NativeAnalog::NumAnalogs>; | ||||
| using TriggerParams = std::array<Common::ParamPackage, Settings::NativeTrigger::NumTriggers>; | ||||
| using ControllerMotionParams = std::array<Common::ParamPackage, Settings::NativeMotion::NumMotions>; | ||||
| using RingAnalogParams = std::array<Common::ParamPackage, max_emulated_controllers>; | ||||
|  | ||||
| using ButtonValues = std::array<Common::Input::ButtonStatus, Settings::NativeButton::NumButtons>; | ||||
| using SticksValues = std::array<Common::Input::StickStatus, Settings::NativeAnalog::NumAnalogs>; | ||||
| using TriggerValues = | ||||
|     std::array<Common::Input::TriggerStatus, Settings::NativeTrigger::NumTriggers>; | ||||
|  | ||||
| struct AnalogSticks { | ||||
|     AnalogStickState left{}; | ||||
|     AnalogStickState right{}; | ||||
| }; | ||||
|  | ||||
|  | ||||
| enum EmulatedDeviceIndex : u8 { | ||||
|     LeftIndex, | ||||
|     RightIndex, | ||||
|     DualIndex, | ||||
|     AllDevices, | ||||
| }; | ||||
|  | ||||
| struct ControllerStatus { | ||||
|     // Data from input_common | ||||
|     ButtonValues button_values{}; | ||||
|     SticksValues stick_values{}; | ||||
|     TriggerValues trigger_values{}; | ||||
|  | ||||
|     // Data for HID services | ||||
|     HomeButtonState home_button_state{}; | ||||
|     CaptureButtonState capture_button_state{}; | ||||
|     NpadButtonState npad_button_state{}; | ||||
|     AnalogSticks analog_stick_state{}; | ||||
|     NpadGcTriggerState gc_trigger_state{}; | ||||
| }; | ||||
|  | ||||
| enum class ControllerTriggerType { | ||||
|     Button, | ||||
|     Stick, | ||||
|     Trigger, | ||||
|     Connected, | ||||
|     Disconnected, | ||||
|     Type, | ||||
|     All, | ||||
| }; | ||||
|  | ||||
| struct ControllerUpdateCallback { | ||||
|     std::function<void(ControllerTriggerType)> on_change; | ||||
|     bool is_npad_service; | ||||
| }; | ||||
|  | ||||
| class SystemController { | ||||
| public: | ||||
|     /** | ||||
|      * Contains all input data (buttons, joysticks, vibration, and motion) within this controller. | ||||
|      * @param npad_id_type npad id type for this specific controller | ||||
|      */ | ||||
|     explicit SystemController(NpadIdType npad_id_type_); | ||||
|     ~SystemController(); | ||||
|  | ||||
|     YUZU_NON_COPYABLE(SystemController); | ||||
|     YUZU_NON_MOVEABLE(SystemController); | ||||
|  | ||||
|     /// Converts the controller type from settings to npad type | ||||
|     static NpadStyleIndex MapSettingsTypeToNPad(Settings::ControllerType type); | ||||
|  | ||||
|     /// Converts npad type to the equivalent of controller type from settings | ||||
|     static Settings::ControllerType MapNPadToSettingsType(NpadStyleIndex type); | ||||
|  | ||||
|     /// Gets the NpadIdType for this controller | ||||
|     NpadIdType GetNpadIdType() const; | ||||
|  | ||||
|     /// Sets the NpadStyleIndex for this controller | ||||
|     void SetNpadStyleIndex(NpadStyleIndex npad_type_); | ||||
|  | ||||
|     /** | ||||
|      * Gets the NpadStyleIndex for this controller | ||||
|      * @param get_temporary_value If true tmp_npad_type will be returned | ||||
|      * @return NpadStyleIndex set on the controller | ||||
|      */ | ||||
|     NpadStyleIndex GetNpadStyleIndex(bool get_temporary_value = false) const; | ||||
|  | ||||
|     /** | ||||
|      * Sets the supported controller types. Disconnects the controller if current type is not | ||||
|      * supported | ||||
|      * @param supported_styles bitflag with supported types | ||||
|      */ | ||||
|     void SetSupportedNpadStyleTag(NpadStyleTag supported_styles); | ||||
|  | ||||
|     /** | ||||
|      * Sets the connected status to true | ||||
|      * @param use_temporary_value If true tmp_npad_type will be used | ||||
|      */ | ||||
|     void Connect(bool use_temporary_value = false); | ||||
|  | ||||
|     /// Sets the connected status to false | ||||
|     void Disconnect(); | ||||
|  | ||||
|     /** | ||||
|      * Is the emulated connected | ||||
|      * @param get_temporary_value If true tmp_is_connected will be returned | ||||
|      * @return true if the controller has the connected status | ||||
|      */ | ||||
|     bool IsConnected(bool get_temporary_value = false) const; | ||||
|  | ||||
|     /// Removes all callbacks created from input devices | ||||
|     void UnloadInput(); | ||||
|  | ||||
|     /** | ||||
|      * Sets the emulated controller into configuring mode | ||||
|      * This prevents the modification of the HID state of the emulated controller by input commands | ||||
|      */ | ||||
|     void EnableConfiguration(); | ||||
|  | ||||
|     /// Returns the emulated controller into normal mode, allowing the modification of the HID state | ||||
|     void DisableConfiguration(); | ||||
|  | ||||
|     /// Enables Home and Screenshot buttons | ||||
|     void EnableSystemButtons(); | ||||
|  | ||||
|     /// Disables Home and Screenshot buttons | ||||
|     void DisableSystemButtons(); | ||||
|  | ||||
|     /// Sets Home and Screenshot buttons to false | ||||
|     void ResetSystemButtons(); | ||||
|  | ||||
|     /// Returns true if the emulated controller is in configuring mode | ||||
|     bool IsConfiguring() const; | ||||
|  | ||||
|     /// Reload all input devices | ||||
|     void ReloadInput(); | ||||
|  | ||||
|     /// Overrides current mapped devices with the stored configuration and reloads all input devices | ||||
|     void ReloadFromSettings(); | ||||
|  | ||||
|     /// Saves the current mapped configuration | ||||
|     void SaveCurrentConfig(); | ||||
|  | ||||
|     /// Reverts any mapped changes made that weren't saved | ||||
|     void RestoreConfig(); | ||||
|  | ||||
|     /// Returns a vector of mapped devices from the mapped button and stick parameters | ||||
|     std::vector<Common::ParamPackage> GetMappedDevices() const; | ||||
|  | ||||
|     // Returns the current mapped button device | ||||
|     Common::ParamPackage GetButtonParam(std::size_t index) const; | ||||
|  | ||||
|     // Returns the current mapped stick device | ||||
|     Common::ParamPackage GetStickParam(std::size_t index) const; | ||||
|  | ||||
|     // Returns the current mapped motion device | ||||
|     Common::ParamPackage GetMotionParam(std::size_t index) const; | ||||
|  | ||||
|     /** | ||||
|      * Updates the current mapped button device | ||||
|      * @param param ParamPackage with controller data to be mapped | ||||
|      */ | ||||
|     void SetButtonParam(std::size_t index, Common::ParamPackage param); | ||||
|  | ||||
|     /** | ||||
|      * Updates the current mapped stick device | ||||
|      * @param param ParamPackage with controller data to be mapped | ||||
|      */ | ||||
|     void SetStickParam(std::size_t index, Common::ParamPackage param); | ||||
|  | ||||
|     /** | ||||
|      * Updates the current mapped motion device | ||||
|      * @param param ParamPackage with controller data to be mapped | ||||
|      */ | ||||
|     void SetMotionParam(std::size_t index, Common::ParamPackage param); | ||||
|  | ||||
|     /// Returns the latest button status from the controller with parameters | ||||
|     ButtonValues GetButtonsValues() const; | ||||
|  | ||||
|     /// Returns the latest analog stick status from the controller with parameters | ||||
|     SticksValues GetSticksValues() const; | ||||
|  | ||||
|     /// Returns the latest trigger status from the controller with parameters | ||||
|     TriggerValues GetTriggersValues() const; | ||||
|  | ||||
|     /// Returns the latest status of button input for the hid::HomeButton service | ||||
|     HomeButtonState GetHomeButtons() const; | ||||
|  | ||||
|     /// Returns the latest status of button input for the hid::CaptureButton service | ||||
|     CaptureButtonState GetCaptureButtons() const; | ||||
|  | ||||
|     /// Returns the latest status of button input for the hid::Npad service | ||||
|     NpadButtonState GetNpadButtons() const; | ||||
|  | ||||
|     /// Returns the latest status of stick input from the mouse | ||||
|     AnalogSticks GetSticks() const; | ||||
|  | ||||
|     /// Returns the latest status of trigger input from the mouse | ||||
|     NpadGcTriggerState GetTriggers() const; | ||||
|  | ||||
|     /** | ||||
|      * Adds a callback to the list of events | ||||
|      * @param update_callback A ConsoleUpdateCallback that will be triggered | ||||
|      * @return an unique key corresponding to the callback index in the list | ||||
|      */ | ||||
|     int SetCallback(ControllerUpdateCallback update_callback); | ||||
|  | ||||
|     /** | ||||
|      * Removes a callback from the list stopping any future events to this object | ||||
|      * @param key Key corresponding to the callback index in the list | ||||
|      */ | ||||
|     void DeleteCallback(int key); | ||||
|  | ||||
| private: | ||||
|     /// creates input devices from params | ||||
|     void LoadDevices(); | ||||
|  | ||||
|     /** | ||||
|      * @param use_temporary_value If true tmp_npad_type will be used | ||||
|      * @return true if the controller style is fullkey | ||||
|      */ | ||||
|     bool IsControllerFullkey(bool use_temporary_value = false) const; | ||||
|  | ||||
|     /** | ||||
|      * Checks the current controller type against the supported_style_tag | ||||
|      * @param use_temporary_value If true tmp_npad_type will be used | ||||
|      * @return true if the controller is supported | ||||
|      */ | ||||
|     bool IsControllerSupported(bool use_temporary_value = false) const; | ||||
|  | ||||
|     /** | ||||
|      * Updates the button status of the controller | ||||
|      * @param callback A CallbackStatus containing the button status | ||||
|      * @param index Button ID of the to be updated | ||||
|      */ | ||||
|     void SetButton(const Common::Input::CallbackStatus& callback, std::size_t index, | ||||
|                    Common::UUID uuid); | ||||
|  | ||||
|     /** | ||||
|      * Updates the analog stick status of the controller | ||||
|      * @param callback A CallbackStatus containing the analog stick status | ||||
|      * @param index stick ID of the to be updated | ||||
|      */ | ||||
|     void SetStick(const Common::Input::CallbackStatus& callback, std::size_t index, | ||||
|                   Common::UUID uuid); | ||||
|  | ||||
|     /** | ||||
|      * Updates the trigger status of the controller | ||||
|      * @param callback A CallbackStatus containing the trigger status | ||||
|      * @param index trigger ID of the to be updated | ||||
|      */ | ||||
|     void SetTrigger(const Common::Input::CallbackStatus& callback, std::size_t index, | ||||
|                     Common::UUID uuid); | ||||
|  | ||||
|     /** | ||||
|      * Triggers a callback that something has changed on the controller status | ||||
|      * @param type Input type of the event to trigger | ||||
|      * @param is_service_update indicates if this event should only be sent to HID services | ||||
|      */ | ||||
|     void TriggerOnChange(ControllerTriggerType type, bool is_service_update); | ||||
|  | ||||
|     const NpadIdType npad_id_type; | ||||
|     NpadStyleIndex npad_type{NpadStyleIndex::None}; | ||||
|     NpadStyleIndex original_npad_type{NpadStyleIndex::None}; | ||||
|     NpadStyleTag supported_style_tag{NpadStyleSet::All}; | ||||
|     bool is_connected{false}; | ||||
|     bool is_configuring{false}; | ||||
|     bool system_buttons_enabled{true}; | ||||
|     f32 motion_sensitivity{Core::HID::MotionInput::IsAtRestStandard}; | ||||
|  | ||||
|     // Temporary values to avoid doing changes while the controller is in configuring mode | ||||
|     NpadStyleIndex tmp_npad_type{NpadStyleIndex::None}; | ||||
|     bool tmp_is_connected{false}; | ||||
|  | ||||
|     ButtonParams button_params; | ||||
|     StickParams stick_params; | ||||
|     TriggerParams trigger_params; | ||||
|     ControllerMotionParams motion_params; | ||||
|     RingAnalogParams ring_params; | ||||
|  | ||||
|     ButtonDevices button_devices; | ||||
|     StickDevices stick_devices; | ||||
|     ControllerMotionDevices motion_devices; | ||||
|     TriggerDevices trigger_devices; | ||||
|  | ||||
|     mutable std::mutex mutex; | ||||
|     mutable std::mutex callback_mutex; | ||||
|     std::unordered_map<int, ControllerUpdateCallback> callback_list; | ||||
|     int last_callback_key = 0; | ||||
|  | ||||
|     // Stores the current status of all controller input | ||||
|     ControllerStatus controller; | ||||
| }; | ||||
|  | ||||
| } // namespace Core::HID | ||||
| @@ -1,7 +1,6 @@ | ||||
| // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later | ||||
|  | ||||
| #include <queue> | ||||
| #include "common/logging/log.h" | ||||
| #include "common/uuid.h" | ||||
| #include "core/core.h" | ||||
| @@ -14,6 +13,9 @@ | ||||
| #include "core/hle/service/server_manager.h" | ||||
|  | ||||
| namespace Service::Friend { | ||||
| Module::Interface::Interface(std::shared_ptr<Module> module_, Core::System& system_, | ||||
|                              const char* name) | ||||
|     : ServiceFramework{system_, name}, module{std::move(module_)} {} | ||||
|  | ||||
| class IFriendService final : public ServiceFramework<IFriendService> { | ||||
| public: | ||||
| @@ -330,11 +332,17 @@ void Module::Interface::CreateNotificationService(HLERequestContext& ctx) { | ||||
|     rb.PushIpcInterface<INotificationService>(system, uuid); | ||||
| } | ||||
|  | ||||
| Module::Interface::Interface(std::shared_ptr<Module> module_, Core::System& system_, | ||||
|                              const char* name) | ||||
|     : ServiceFramework{system_, name}, module{std::move(module_)} {} | ||||
| Friend::Friend(std::shared_ptr<Module> module_, Core::System& system_, const char* name) | ||||
|     : Interface(std::move(module_), system_, name) { | ||||
|     static const FunctionInfo functions[] = { | ||||
|         {0, &Friend::CreateFriendService, "CreateFriendService"}, | ||||
|         {1, &Friend::CreateNotificationService, "CreateNotificationService"}, | ||||
|         {2, nullptr, "CreateDaemonSuspendSessionService"}, | ||||
|     }; | ||||
|     RegisterHandlers(functions); | ||||
| } | ||||
|  | ||||
| Module::Interface::~Interface() = default; | ||||
| Friend::~Friend() = default; | ||||
|  | ||||
| void LoopProcess(Core::System& system) { | ||||
|     auto server_manager = std::make_unique<ServerManager>(system); | ||||
|   | ||||
| @@ -1,20 +0,0 @@ | ||||
| // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later | ||||
|  | ||||
| #include "core/hle/service/friend/friend_interface.h" | ||||
|  | ||||
| namespace Service::Friend { | ||||
|  | ||||
| Friend::Friend(std::shared_ptr<Module> module_, Core::System& system_, const char* name) | ||||
|     : Interface(std::move(module_), system_, name) { | ||||
|     static const FunctionInfo functions[] = { | ||||
|         {0, &Friend::CreateFriendService, "CreateFriendService"}, | ||||
|         {1, &Friend::CreateNotificationService, "CreateNotificationService"}, | ||||
|         {2, nullptr, "CreateDaemonSuspendSessionService"}, | ||||
|     }; | ||||
|     RegisterHandlers(functions); | ||||
| } | ||||
|  | ||||
| Friend::~Friend() = default; | ||||
|  | ||||
| } // namespace Service::Friend | ||||
| @@ -1,16 +0,0 @@ | ||||
| // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "core/hle/service/friend/friend.h" | ||||
|  | ||||
| namespace Service::Friend { | ||||
|  | ||||
| class Friend final : public Module::Interface { | ||||
| public: | ||||
|     explicit Friend(std::shared_ptr<Module> module_, Core::System& system_, const char* name); | ||||
|     ~Friend() override; | ||||
| }; | ||||
|  | ||||
| } // namespace Service::Friend | ||||
							
								
								
									
										14
									
								
								src/core/hle/service/friend/friend_results.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								src/core/hle/service/friend/friend_results.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | ||||
| // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "core/hle/result.h" | ||||
|  | ||||
| namespace Service::Friend { | ||||
|  | ||||
| constexpr Result NotInitialized{ErrorModule::Account, 1}; | ||||
| constexpr Result InvalidArgument{ErrorModule::Account, 2}; | ||||
| constexpr Result NoNotifications{ErrorModule::Account, 15}; | ||||
|  | ||||
| } // namespace Service::Friend | ||||
							
								
								
									
										184
									
								
								src/core/hle/service/friend/friend_service.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										184
									
								
								src/core/hle/service/friend/friend_service.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,184 @@ | ||||
| // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later | ||||
|  | ||||
| #include "common/logging/log.h" | ||||
| #include "common/uuid.h" | ||||
| #include "core/hle/ipc_helpers.h" | ||||
| #include "core/hle/service/friend/friend_results.h" | ||||
| #include "core/hle/service/friend/friend_service.h" | ||||
| #include "core/hle/service/friend/friend_types.h" | ||||
|  | ||||
| namespace Service::Friend { | ||||
|  | ||||
| IFriendService::IFriendService(Core::System& system_) | ||||
|     : ServiceFramework{system_, "IFriendService"}, service_context{system, "IFriendService"} { | ||||
|     // clang-format off | ||||
|         static const FunctionInfo functions[] = { | ||||
|             {0, &IFriendService::GetCompletionEvent, "GetCompletionEvent"}, | ||||
|             {1, nullptr, "Cancel"}, | ||||
|             {10100, nullptr, "GetFriendListIds"}, | ||||
|             {10101, &IFriendService::GetFriendList, "GetFriendList"}, | ||||
|             {10102, nullptr, "UpdateFriendInfo"}, | ||||
|             {10110, nullptr, "GetFriendProfileImage"}, | ||||
|             {10120, &IFriendService::CheckFriendListAvailability, "CheckFriendListAvailability"}, | ||||
|             {10121, nullptr, "EnsureFriendListAvailable"}, | ||||
|             {10200, nullptr, "SendFriendRequestForApplication"}, | ||||
|             {10211, nullptr, "AddFacedFriendRequestForApplication"}, | ||||
|             {10400, &IFriendService::GetBlockedUserListIds, "GetBlockedUserListIds"}, | ||||
|             {10420, nullptr, "IsBlockedUserListCacheAvailable"}, | ||||
|             {10421, nullptr, "EnsureBlockedUserListAvailable"}, | ||||
|             {10500, nullptr, "GetProfileList"}, | ||||
|             {10600, nullptr, "DeclareOpenOnlinePlaySession"}, | ||||
|             {10601, &IFriendService::DeclareCloseOnlinePlaySession, "DeclareCloseOnlinePlaySession"}, | ||||
|             {10610, &IFriendService::UpdateUserPresence, "UpdateUserPresence"}, | ||||
|             {10700, &IFriendService::GetPlayHistoryRegistrationKey, "GetPlayHistoryRegistrationKey"}, | ||||
|             {10701, nullptr, "GetPlayHistoryRegistrationKeyWithNetworkServiceAccountId"}, | ||||
|             {10702, nullptr, "AddPlayHistory"}, | ||||
|             {11000, nullptr, "GetProfileImageUrl"}, | ||||
|             {20100, nullptr, "GetFriendCount"}, | ||||
|             {20101, nullptr, "GetNewlyFriendCount"}, | ||||
|             {20102, nullptr, "GetFriendDetailedInfo"}, | ||||
|             {20103, nullptr, "SyncFriendList"}, | ||||
|             {20104, nullptr, "RequestSyncFriendList"}, | ||||
|             {20110, nullptr, "LoadFriendSetting"}, | ||||
|             {20200, nullptr, "GetReceivedFriendRequestCount"}, | ||||
|             {20201, nullptr, "GetFriendRequestList"}, | ||||
|             {20300, nullptr, "GetFriendCandidateList"}, | ||||
|             {20301, nullptr, "GetNintendoNetworkIdInfo"}, | ||||
|             {20302, nullptr, "GetSnsAccountLinkage"}, | ||||
|             {20303, nullptr, "GetSnsAccountProfile"}, | ||||
|             {20304, nullptr, "GetSnsAccountFriendList"}, | ||||
|             {20400, nullptr, "GetBlockedUserList"}, | ||||
|             {20401, nullptr, "SyncBlockedUserList"}, | ||||
|             {20500, nullptr, "GetProfileExtraList"}, | ||||
|             {20501, nullptr, "GetRelationship"}, | ||||
|             {20600, nullptr, "GetUserPresenceView"}, | ||||
|             {20700, nullptr, "GetPlayHistoryList"}, | ||||
|             {20701, nullptr, "GetPlayHistoryStatistics"}, | ||||
|             {20800, nullptr, "LoadUserSetting"}, | ||||
|             {20801, nullptr, "SyncUserSetting"}, | ||||
|             {20900, nullptr, "RequestListSummaryOverlayNotification"}, | ||||
|             {21000, nullptr, "GetExternalApplicationCatalog"}, | ||||
|             {22000, nullptr, "GetReceivedFriendInvitationList"}, | ||||
|             {22001, nullptr, "GetReceivedFriendInvitationDetailedInfo"}, | ||||
|             {22010, nullptr, "GetReceivedFriendInvitationCountCache"}, | ||||
|             {30100, nullptr, "DropFriendNewlyFlags"}, | ||||
|             {30101, nullptr, "DeleteFriend"}, | ||||
|             {30110, nullptr, "DropFriendNewlyFlag"}, | ||||
|             {30120, nullptr, "ChangeFriendFavoriteFlag"}, | ||||
|             {30121, nullptr, "ChangeFriendOnlineNotificationFlag"}, | ||||
|             {30200, nullptr, "SendFriendRequest"}, | ||||
|             {30201, nullptr, "SendFriendRequestWithApplicationInfo"}, | ||||
|             {30202, nullptr, "CancelFriendRequest"}, | ||||
|             {30203, nullptr, "AcceptFriendRequest"}, | ||||
|             {30204, nullptr, "RejectFriendRequest"}, | ||||
|             {30205, nullptr, "ReadFriendRequest"}, | ||||
|             {30210, nullptr, "GetFacedFriendRequestRegistrationKey"}, | ||||
|             {30211, nullptr, "AddFacedFriendRequest"}, | ||||
|             {30212, nullptr, "CancelFacedFriendRequest"}, | ||||
|             {30213, nullptr, "GetFacedFriendRequestProfileImage"}, | ||||
|             {30214, nullptr, "GetFacedFriendRequestProfileImageFromPath"}, | ||||
|             {30215, nullptr, "SendFriendRequestWithExternalApplicationCatalogId"}, | ||||
|             {30216, nullptr, "ResendFacedFriendRequest"}, | ||||
|             {30217, nullptr, "SendFriendRequestWithNintendoNetworkIdInfo"}, | ||||
|             {30300, nullptr, "GetSnsAccountLinkPageUrl"}, | ||||
|             {30301, nullptr, "UnlinkSnsAccount"}, | ||||
|             {30400, nullptr, "BlockUser"}, | ||||
|             {30401, nullptr, "BlockUserWithApplicationInfo"}, | ||||
|             {30402, nullptr, "UnblockUser"}, | ||||
|             {30500, nullptr, "GetProfileExtraFromFriendCode"}, | ||||
|             {30700, nullptr, "DeletePlayHistory"}, | ||||
|             {30810, nullptr, "ChangePresencePermission"}, | ||||
|             {30811, nullptr, "ChangeFriendRequestReception"}, | ||||
|             {30812, nullptr, "ChangePlayLogPermission"}, | ||||
|             {30820, nullptr, "IssueFriendCode"}, | ||||
|             {30830, nullptr, "ClearPlayLog"}, | ||||
|             {30900, nullptr, "SendFriendInvitation"}, | ||||
|             {30910, nullptr, "ReadFriendInvitation"}, | ||||
|             {30911, nullptr, "ReadAllFriendInvitations"}, | ||||
|             {40100, nullptr, "DeleteFriendListCache"}, | ||||
|             {40400, nullptr, "DeleteBlockedUserListCache"}, | ||||
|             {49900, nullptr, "DeleteNetworkServiceAccountCache"}, | ||||
|         }; | ||||
|     // clang-format on | ||||
|  | ||||
|     RegisterHandlers(functions); | ||||
|  | ||||
|     completion_event = service_context.CreateEvent("IFriendService:CompletionEvent"); | ||||
| } | ||||
|  | ||||
| IFriendService::~IFriendService() { | ||||
|     service_context.CloseEvent(completion_event); | ||||
| } | ||||
|  | ||||
| void IFriendService::GetCompletionEvent(Kernel::HLERequestContext& ctx) { | ||||
|     LOG_DEBUG(Service_Friend, "called"); | ||||
|  | ||||
|     IPC::ResponseBuilder rb{ctx, 2, 1}; | ||||
|     rb.Push(ResultSuccess); | ||||
|     rb.PushCopyObjects(completion_event->GetReadableEvent()); | ||||
| } | ||||
|  | ||||
| void IFriendService::GetBlockedUserListIds(Kernel::HLERequestContext& ctx) { | ||||
|     // This is safe to stub, as there should be no adverse consequences from reporting no | ||||
|     // blocked users. | ||||
|     LOG_WARNING(Service_Friend, "(STUBBED) called"); | ||||
|     IPC::ResponseBuilder rb{ctx, 3}; | ||||
|     rb.Push(ResultSuccess); | ||||
|     rb.Push<u32>(0); // Indicates there are no blocked users | ||||
| } | ||||
|  | ||||
| void IFriendService::DeclareCloseOnlinePlaySession(Kernel::HLERequestContext& ctx) { | ||||
|     // Stub used by Splatoon 2 | ||||
|     LOG_WARNING(Service_Friend, "(STUBBED) called"); | ||||
|     IPC::ResponseBuilder rb{ctx, 2}; | ||||
|     rb.Push(ResultSuccess); | ||||
| } | ||||
|  | ||||
| void IFriendService::UpdateUserPresence(Kernel::HLERequestContext& ctx) { | ||||
|     // Stub used by Retro City Rampage | ||||
|     LOG_WARNING(Service_Friend, "(STUBBED) called"); | ||||
|     IPC::ResponseBuilder rb{ctx, 2}; | ||||
|     rb.Push(ResultSuccess); | ||||
| } | ||||
|  | ||||
| void IFriendService::GetPlayHistoryRegistrationKey(Kernel::HLERequestContext& ctx) { | ||||
|     IPC::RequestParser rp{ctx}; | ||||
|     const auto local_play = rp.Pop<bool>(); | ||||
|     const auto uuid = rp.PopRaw<Common::UUID>(); | ||||
|  | ||||
|     LOG_WARNING(Service_Friend, "(STUBBED) called, local_play={}, uuid=0x{}", local_play, | ||||
|                 uuid.RawString()); | ||||
|  | ||||
|     IPC::ResponseBuilder rb{ctx, 2}; | ||||
|     rb.Push(ResultSuccess); | ||||
| } | ||||
|  | ||||
| void IFriendService::GetFriendList(Kernel::HLERequestContext& ctx) { | ||||
|     IPC::RequestParser rp{ctx}; | ||||
|     const auto friend_offset = rp.Pop<u32>(); | ||||
|     const auto uuid = rp.PopRaw<Common::UUID>(); | ||||
|     [[maybe_unused]] const auto filter = rp.PopRaw<SizedFriendFilter>(); | ||||
|     const auto pid = rp.Pop<u64>(); | ||||
|     LOG_WARNING(Service_Friend, "(STUBBED) called, offset={}, uuid=0x{}, pid={}", friend_offset, | ||||
|                 uuid.RawString(), pid); | ||||
|  | ||||
|     IPC::ResponseBuilder rb{ctx, 3}; | ||||
|     rb.Push(ResultSuccess); | ||||
|  | ||||
|     rb.Push<u32>(0); // Friend count | ||||
|     // TODO(ogniK): Return a buffer of u64s which are the "NetworkServiceAccountId" | ||||
| } | ||||
|  | ||||
| void IFriendService::CheckFriendListAvailability(Kernel::HLERequestContext& ctx) { | ||||
|     IPC::RequestParser rp{ctx}; | ||||
|     const auto uuid{rp.PopRaw<Common::UUID>()}; | ||||
|  | ||||
|     LOG_WARNING(Service_Friend, "(STUBBED) called, uuid=0x{}", uuid.RawString()); | ||||
|  | ||||
|     IPC::ResponseBuilder rb{ctx, 3}; | ||||
|     rb.Push(ResultSuccess); | ||||
|     rb.Push(true); | ||||
| } | ||||
|  | ||||
| } // namespace Service::Friend | ||||
							
								
								
									
										31
									
								
								src/core/hle/service/friend/friend_service.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								src/core/hle/service/friend/friend_service.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,31 @@ | ||||
| // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "core/hle/service/friend/friend.h" | ||||
| #include "core/hle/service/kernel_helpers.h" | ||||
| #include "core/hle/service/service.h" | ||||
|  | ||||
| namespace Service::Friend { | ||||
|  | ||||
| class IFriendService final : public ServiceFramework<IFriendService> { | ||||
| public: | ||||
|     explicit IFriendService(Core::System& system_); | ||||
|     ~IFriendService() override; | ||||
|  | ||||
| private: | ||||
|     void GetCompletionEvent(Kernel::HLERequestContext& ctx); | ||||
|     void GetFriendList(Kernel::HLERequestContext& ctx); | ||||
|     void CheckFriendListAvailability(Kernel::HLERequestContext& ctx); | ||||
|     void GetBlockedUserListIds(Kernel::HLERequestContext& ctx); | ||||
|     void DeclareCloseOnlinePlaySession(Kernel::HLERequestContext& ctx); | ||||
|     void UpdateUserPresence(Kernel::HLERequestContext& ctx); | ||||
|     void GetPlayHistoryRegistrationKey(Kernel::HLERequestContext& ctx); | ||||
|  | ||||
|     KernelHelpers::ServiceContext service_context; | ||||
|  | ||||
|     Kernel::KEvent* completion_event; | ||||
| }; | ||||
|  | ||||
| } // namespace Service::Friend | ||||
							
								
								
									
										46
									
								
								src/core/hle/service/friend/friend_types.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								src/core/hle/service/friend/friend_types.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,46 @@ | ||||
| // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include <array> | ||||
| #include "common/common_types.h" | ||||
|  | ||||
| namespace Service::Friend { | ||||
|  | ||||
| enum class PresenceFilter : u32 { | ||||
|     None = 0, | ||||
|     Online = 1, | ||||
|     OnlinePlay = 2, | ||||
|     OnlineOrOnlinePlay = 3, | ||||
| }; | ||||
|  | ||||
| struct SizedFriendFilter { | ||||
|     PresenceFilter presence; | ||||
|     u8 is_favorite; | ||||
|     u8 same_app; | ||||
|     u8 same_app_played; | ||||
|     u8 arbitary_app_played; | ||||
|     u64 group_id; | ||||
| }; | ||||
| static_assert(sizeof(SizedFriendFilter) == 0x10, "SizedFriendFilter is an invalid size"); | ||||
|  | ||||
| enum class NotificationTypes : u32 { | ||||
|     HasUpdatedFriendsList = 0x65, | ||||
|     HasReceivedFriendRequest = 0x1, | ||||
| }; | ||||
|  | ||||
| struct SizedNotificationInfo { | ||||
|     NotificationTypes notification_type; | ||||
|     INSERT_PADDING_WORDS( | ||||
|         1); // TODO(ogniK): This doesn't seem to be used within any IPC returns as of now | ||||
|     u64_le account_id; | ||||
| }; | ||||
| static_assert(sizeof(SizedNotificationInfo) == 0x10, "SizedNotificationInfo is an incorrect size"); | ||||
|  | ||||
| struct States { | ||||
|     bool has_updated_friends; | ||||
|     bool has_received_friend_request; | ||||
| }; | ||||
|  | ||||
| } // namespace Service::Friend | ||||
							
								
								
									
										83
									
								
								src/core/hle/service/friend/notification_service.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								src/core/hle/service/friend/notification_service.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,83 @@ | ||||
| // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later | ||||
|  | ||||
| #include "common/logging/log.h" | ||||
| #include "core/hle/ipc_helpers.h" | ||||
| #include "core/hle/service/friend/friend_results.h" | ||||
| #include "core/hle/service/friend/friend_types.h" | ||||
| #include "core/hle/service/friend/notification_service.h" | ||||
|  | ||||
| namespace Service::Friend { | ||||
|  | ||||
| INotificationService::INotificationService(Core::System& system_, Common::UUID uuid_) | ||||
|     : ServiceFramework{system_, "INotificationService"}, uuid{uuid_}, service_context{ | ||||
|                                                                           system_, | ||||
|                                                                           "INotificationService"} { | ||||
|     // clang-format off | ||||
|         static const FunctionInfo functions[] = { | ||||
|             {0, &INotificationService::GetEvent, "GetEvent"}, | ||||
|             {1, &INotificationService::Clear, "Clear"}, | ||||
|             {2, &INotificationService::Pop, "Pop"} | ||||
|         }; | ||||
|     // clang-format on | ||||
|  | ||||
|     RegisterHandlers(functions); | ||||
|  | ||||
|     notification_event = service_context.CreateEvent("INotificationService:NotifyEvent"); | ||||
| } | ||||
|  | ||||
| INotificationService::~INotificationService() { | ||||
|     service_context.CloseEvent(notification_event); | ||||
| } | ||||
|  | ||||
| void INotificationService::GetEvent(Kernel::HLERequestContext& ctx) { | ||||
|     LOG_DEBUG(Service_Friend, "called"); | ||||
|  | ||||
|     IPC::ResponseBuilder rb{ctx, 2, 1}; | ||||
|     rb.Push(ResultSuccess); | ||||
|     rb.PushCopyObjects(notification_event->GetReadableEvent()); | ||||
| } | ||||
|  | ||||
| void INotificationService::Clear(Kernel::HLERequestContext& ctx) { | ||||
|     LOG_DEBUG(Service_Friend, "called"); | ||||
|     while (!notifications.empty()) { | ||||
|         notifications.pop(); | ||||
|     } | ||||
|     std::memset(&states, 0, sizeof(States)); | ||||
|  | ||||
|     IPC::ResponseBuilder rb{ctx, 2}; | ||||
|     rb.Push(ResultSuccess); | ||||
| } | ||||
|  | ||||
| void INotificationService::Pop(Kernel::HLERequestContext& ctx) { | ||||
|     LOG_DEBUG(Service_Friend, "called"); | ||||
|  | ||||
|     if (notifications.empty()) { | ||||
|         LOG_ERROR(Service_Friend, "No notifications in queue!"); | ||||
|         IPC::ResponseBuilder rb{ctx, 2}; | ||||
|         rb.Push(NoNotifications); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     const auto notification = notifications.front(); | ||||
|     notifications.pop(); | ||||
|  | ||||
|     switch (notification.notification_type) { | ||||
|     case NotificationTypes::HasUpdatedFriendsList: | ||||
|         states.has_updated_friends = false; | ||||
|         break; | ||||
|     case NotificationTypes::HasReceivedFriendRequest: | ||||
|         states.has_received_friend_request = false; | ||||
|         break; | ||||
|     default: | ||||
|         // HOS seems not have an error case for an unknown notification | ||||
|         LOG_WARNING(Service_Friend, "Unknown notification {:08X}", notification.notification_type); | ||||
|         break; | ||||
|     } | ||||
|  | ||||
|     IPC::ResponseBuilder rb{ctx, 6}; | ||||
|     rb.Push(ResultSuccess); | ||||
|     rb.PushRaw<SizedNotificationInfo>(notification); | ||||
| } | ||||
|  | ||||
| } // namespace Service::Friend | ||||
							
								
								
									
										32
									
								
								src/core/hle/service/friend/notification_service.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								src/core/hle/service/friend/notification_service.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,32 @@ | ||||
| // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later | ||||
|  | ||||
| #pragma once | ||||
| #include <queue> | ||||
|  | ||||
| #include "common/uuid.h" | ||||
| #include "core/hle/service/friend/friend_types.h" | ||||
| #include "core/hle/service/kernel_helpers.h" | ||||
| #include "core/hle/service/service.h" | ||||
|  | ||||
| namespace Service::Friend { | ||||
|  | ||||
| class INotificationService final : public ServiceFramework<INotificationService> { | ||||
| public: | ||||
|     explicit INotificationService(Core::System& system_, Common::UUID uuid_); | ||||
|     ~INotificationService() override; | ||||
|  | ||||
| private: | ||||
|     void GetEvent(Kernel::HLERequestContext& ctx); | ||||
|     void Clear(Kernel::HLERequestContext& ctx); | ||||
|     void Pop(Kernel::HLERequestContext& ctx); | ||||
|  | ||||
|     Common::UUID uuid; | ||||
|     KernelHelpers::ServiceContext service_context; | ||||
|  | ||||
|     Kernel::KEvent* notification_event; | ||||
|     std::queue<SizedNotificationInfo> notifications; | ||||
|     States states{}; | ||||
| }; | ||||
|  | ||||
| } // namespace Service::Friend | ||||
| @@ -24,6 +24,7 @@ ClusteringProcessor::ClusteringProcessor(Core::HID::HIDCore& hid_core_, | ||||
|  | ||||
|     Core::HID::ControllerUpdateCallback engine_callback{ | ||||
|         .on_change = [this](Core::HID::ControllerTriggerType type) { OnControllerUpdate(type); }, | ||||
|         .is_npad_service = true, | ||||
|     }; | ||||
|     callback_key = npad_device->SetCallback(engine_callback); | ||||
| } | ||||
|   | ||||
| @@ -6,7 +6,7 @@ | ||||
| #include <QStandardItemModel> | ||||
| #include <QTimer> | ||||
|  | ||||
| #include "core/hid/system_controller.h" | ||||
| #include "core/hid/emulated_controller.h" | ||||
| #include "core/hid/hid_core.h" | ||||
|  | ||||
| #include "ui_configure_hotkeys.h" | ||||
| @@ -42,7 +42,7 @@ ConfigureHotkeys::ConfigureHotkeys(Core::HID::HIDCore& hid_core, QWidget* parent | ||||
|             &ConfigureHotkeys::RestoreDefaults); | ||||
|     connect(ui->button_clear_all, &QPushButton::clicked, this, &ConfigureHotkeys::ClearAll); | ||||
|  | ||||
|     controller = hid_core.GetSystemController(Core::HID::NpadIdType::Player1); | ||||
|     controller = hid_core.GetEmulatedController(Core::HID::NpadIdType::Player1); | ||||
|  | ||||
|     connect(timeout_timer.get(), &QTimer::timeout, [this] { SetPollingResult({}, true); }); | ||||
|  | ||||
|   | ||||
| @@ -12,7 +12,7 @@ class ParamPackage; | ||||
|  | ||||
| namespace Core::HID { | ||||
| class HIDCore; | ||||
| class SystemController; | ||||
| class EmulatedController; | ||||
| enum class NpadButton : u64; | ||||
| } // namespace Core::HID | ||||
|  | ||||
| @@ -60,7 +60,7 @@ private: | ||||
|  | ||||
|     void SetPollingResult(Core::HID::NpadButton button, bool cancel); | ||||
|     QString GetButtonCombinationName(Core::HID::NpadButton button, bool home, bool capture) const; | ||||
|     Core::HID::SystemController* controller; | ||||
|     Core::HID::EmulatedController* controller; | ||||
|     std::unique_ptr<QTimer> timeout_timer; | ||||
|     std::unique_ptr<QTimer> poll_timer; | ||||
|     std::optional<std::function<void(Core::HID::NpadButton, bool)>> input_setter; | ||||
|   | ||||
| @@ -12,7 +12,7 @@ | ||||
| #include <QTimer> | ||||
| #include "common/assert.h" | ||||
| #include "common/param_package.h" | ||||
| #include "core/hid/system_controller.h" | ||||
| #include "core/hid/emulated_controller.h" | ||||
| #include "core/hid/hid_core.h" | ||||
| #include "core/hid/hid_types.h" | ||||
| #include "input_common/drivers/keyboard.h" | ||||
| @@ -297,24 +297,24 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i | ||||
|       timeout_timer(std::make_unique<QTimer>()), | ||||
|       poll_timer(std::make_unique<QTimer>()), bottom_row{bottom_row_}, hid_core{hid_core_} { | ||||
|     if (player_index == 0) { | ||||
|         auto* system_controller_p1 = | ||||
|             hid_core.GetSystemController(Core::HID::NpadIdType::Player1); | ||||
|         auto* system_controller_handheld = | ||||
|             hid_core.GetSystemController(Core::HID::NpadIdType::Handheld); | ||||
|         system_controller_p1->SaveCurrentConfig(); | ||||
|         system_controller_p1->EnableConfiguration(); | ||||
|         system_controller_handheld->SaveCurrentConfig(); | ||||
|         system_controller_handheld->EnableConfiguration(); | ||||
|         if (system_controller_handheld->IsConnected(true)) { | ||||
|             system_controller_p1->Disconnect(); | ||||
|             system_controller = system_controller_handheld; | ||||
|         auto* emulated_controller_p1 = | ||||
|             hid_core.GetEmulatedController(Core::HID::NpadIdType::Player1); | ||||
|         auto* emulated_controller_handheld = | ||||
|             hid_core.GetEmulatedController(Core::HID::NpadIdType::Handheld); | ||||
|         emulated_controller_p1->SaveCurrentConfig(); | ||||
|         emulated_controller_p1->EnableConfiguration(); | ||||
|         emulated_controller_handheld->SaveCurrentConfig(); | ||||
|         emulated_controller_handheld->EnableConfiguration(); | ||||
|         if (emulated_controller_handheld->IsConnected(true)) { | ||||
|             emulated_controller_p1->Disconnect(); | ||||
|             emulated_controller = emulated_controller_handheld; | ||||
|         } else { | ||||
|             system_controller = system_controller_p1; | ||||
|             emulated_controller = emulated_controller_p1; | ||||
|         } | ||||
|     } else { | ||||
|         system_controller = hid_core.GetSystemControllerByIndex(player_index); | ||||
|         system_controller->SaveCurrentConfig(); | ||||
|         system_controller->EnableConfiguration(); | ||||
|         emulated_controller = hid_core.GetEmulatedControllerByIndex(player_index); | ||||
|         emulated_controller->SaveCurrentConfig(); | ||||
|         emulated_controller->EnableConfiguration(); | ||||
|     } | ||||
|     ui->setupUi(this); | ||||
|  | ||||
| @@ -357,7 +357,7 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i | ||||
|     analog_map_range_groupbox = {ui->buttonLStickRangeGroup, ui->buttonRStickRangeGroup}; | ||||
|     analog_map_range_spinbox = {ui->spinboxLStickRange, ui->spinboxRStickRange}; | ||||
|  | ||||
|     ui->controllerFrame->SetController(system_controller->GetNpadIdType()); | ||||
|     ui->controllerFrame->SetController(emulated_controller); | ||||
|  | ||||
|     for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; ++button_id) { | ||||
|         auto* const button = button_map[button_id]; | ||||
| @@ -370,7 +370,7 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i | ||||
|             HandleClick( | ||||
|                 button, button_id, | ||||
|                 [=, this](const Common::ParamPackage& params) { | ||||
|                     system_controller->SetButtonParam(button_id, params); | ||||
|                     emulated_controller->SetButtonParam(button_id, params); | ||||
|                 }, | ||||
|                 InputCommon::Polling::InputType::Button); | ||||
|         }); | ||||
| @@ -379,9 +379,9 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i | ||||
|         connect(button, &QPushButton::customContextMenuRequested, | ||||
|                 [=, this](const QPoint& menu_location) { | ||||
|                     QMenu context_menu; | ||||
|                     Common::ParamPackage param = system_controller->GetButtonParam(button_id); | ||||
|                     Common::ParamPackage param = emulated_controller->GetButtonParam(button_id); | ||||
|                     context_menu.addAction(tr("Clear"), [&] { | ||||
|                         system_controller->SetButtonParam(button_id, {}); | ||||
|                         emulated_controller->SetButtonParam(button_id, {}); | ||||
|                         button_map[button_id]->setText(tr("[not set]")); | ||||
|                     }); | ||||
|                     if (param.Has("code") || param.Has("button") || param.Has("hat")) { | ||||
| @@ -389,19 +389,19 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i | ||||
|                             const bool invert_value = !param.Get("inverted", false); | ||||
|                             param.Set("inverted", invert_value); | ||||
|                             button_map[button_id]->setText(ButtonToText(param)); | ||||
|                             system_controller->SetButtonParam(button_id, param); | ||||
|                             emulated_controller->SetButtonParam(button_id, param); | ||||
|                         }); | ||||
|                         context_menu.addAction(tr("Toggle button"), [&] { | ||||
|                             const bool toggle_value = !param.Get("toggle", false); | ||||
|                             param.Set("toggle", toggle_value); | ||||
|                             button_map[button_id]->setText(ButtonToText(param)); | ||||
|                             system_controller->SetButtonParam(button_id, param); | ||||
|                             emulated_controller->SetButtonParam(button_id, param); | ||||
|                         }); | ||||
|                         context_menu.addAction(tr("Turbo button"), [&] { | ||||
|                             const bool turbo_value = !param.Get("turbo", false); | ||||
|                             param.Set("turbo", turbo_value); | ||||
|                             button_map[button_id]->setText(ButtonToText(param)); | ||||
|                             system_controller->SetButtonParam(button_id, param); | ||||
|                             emulated_controller->SetButtonParam(button_id, param); | ||||
|                         }); | ||||
|                     } | ||||
|                     if (param.Has("axis")) { | ||||
| @@ -409,13 +409,13 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i | ||||
|                             const bool toggle_value = !(param.Get("invert", "+") == "-"); | ||||
|                             param.Set("invert", toggle_value ? "-" : "+"); | ||||
|                             button_map[button_id]->setText(ButtonToText(param)); | ||||
|                             system_controller->SetButtonParam(button_id, param); | ||||
|                             emulated_controller->SetButtonParam(button_id, param); | ||||
|                         }); | ||||
|                         context_menu.addAction(tr("Invert button"), [&] { | ||||
|                             const bool invert_value = !param.Get("inverted", false); | ||||
|                             param.Set("inverted", invert_value); | ||||
|                             button_map[button_id]->setText(ButtonToText(param)); | ||||
|                             system_controller->SetButtonParam(button_id, param); | ||||
|                             emulated_controller->SetButtonParam(button_id, param); | ||||
|                         }); | ||||
|                         context_menu.addAction(tr("Set threshold"), [&] { | ||||
|                             const int button_threshold = | ||||
| @@ -431,13 +431,13 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i | ||||
|                             if (button_id == Settings::NativeButton::ZR) { | ||||
|                                 ui->sliderZRThreshold->setValue(new_threshold); | ||||
|                             } | ||||
|                             system_controller->SetButtonParam(button_id, param); | ||||
|                             emulated_controller->SetButtonParam(button_id, param); | ||||
|                         }); | ||||
|                         context_menu.addAction(tr("Toggle axis"), [&] { | ||||
|                             const bool toggle_value = !param.Get("toggle", false); | ||||
|                             param.Set("toggle", toggle_value); | ||||
|                             button_map[button_id]->setText(ButtonToText(param)); | ||||
|                             system_controller->SetButtonParam(button_id, param); | ||||
|                             emulated_controller->SetButtonParam(button_id, param); | ||||
|                         }); | ||||
|                     } | ||||
|                     context_menu.exec(button_map[button_id]->mapToGlobal(menu_location)); | ||||
| @@ -454,7 +454,7 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i | ||||
|             HandleClick( | ||||
|                 button, motion_id, | ||||
|                 [=, this](const Common::ParamPackage& params) { | ||||
|                     system_controller->SetMotionParam(motion_id, params); | ||||
|                     emulated_controller->SetMotionParam(motion_id, params); | ||||
|                 }, | ||||
|                 InputCommon::Polling::InputType::Motion); | ||||
|         }); | ||||
| @@ -464,9 +464,9 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i | ||||
|         connect(button, &QPushButton::customContextMenuRequested, | ||||
|                 [=, this](const QPoint& menu_location) { | ||||
|                     QMenu context_menu; | ||||
|                     Common::ParamPackage param = system_controller->GetMotionParam(motion_id); | ||||
|                     Common::ParamPackage param = emulated_controller->GetMotionParam(motion_id); | ||||
|                     context_menu.addAction(tr("Clear"), [&] { | ||||
|                         system_controller->SetMotionParam(motion_id, {}); | ||||
|                         emulated_controller->SetMotionParam(motion_id, {}); | ||||
|                         motion_map[motion_id]->setText(tr("[not set]")); | ||||
|                     }); | ||||
|                     if (param.Has("motion")) { | ||||
| @@ -477,7 +477,7 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i | ||||
|                                 this, tr("Set threshold"), tr("Choose a value between 0% and 100%"), | ||||
|                                 gyro_threshold, 0, 100); | ||||
|                             param.Set("threshold", new_threshold / 1000.0f); | ||||
|                             system_controller->SetMotionParam(motion_id, param); | ||||
|                             emulated_controller->SetMotionParam(motion_id, param); | ||||
|                         }); | ||||
|                         context_menu.addAction(tr("Calibrate sensor"), [&] { | ||||
|                             emulated_controller->StartMotionCalibration(); | ||||
| @@ -489,21 +489,21 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i | ||||
|  | ||||
|     connect(ui->sliderZLThreshold, &QSlider::valueChanged, [=, this] { | ||||
|         Common::ParamPackage param = | ||||
|             system_controller->GetButtonParam(Settings::NativeButton::ZL); | ||||
|             emulated_controller->GetButtonParam(Settings::NativeButton::ZL); | ||||
|         if (param.Has("threshold")) { | ||||
|             const auto slider_value = ui->sliderZLThreshold->value(); | ||||
|             param.Set("threshold", slider_value / 100.0f); | ||||
|             system_controller->SetButtonParam(Settings::NativeButton::ZL, param); | ||||
|             emulated_controller->SetButtonParam(Settings::NativeButton::ZL, param); | ||||
|         } | ||||
|     }); | ||||
|  | ||||
|     connect(ui->sliderZRThreshold, &QSlider::valueChanged, [=, this] { | ||||
|         Common::ParamPackage param = | ||||
|             system_controller->GetButtonParam(Settings::NativeButton::ZR); | ||||
|             emulated_controller->GetButtonParam(Settings::NativeButton::ZR); | ||||
|         if (param.Has("threshold")) { | ||||
|             const auto slider_value = ui->sliderZRThreshold->value(); | ||||
|             param.Set("threshold", slider_value / 100.0f); | ||||
|             system_controller->SetButtonParam(Settings::NativeButton::ZR, param); | ||||
|             emulated_controller->SetButtonParam(Settings::NativeButton::ZR, param); | ||||
|         } | ||||
|     }); | ||||
|  | ||||
| @@ -531,7 +531,7 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i | ||||
|                 HandleClick( | ||||
|                     analog_map_buttons[analog_id][sub_button_id], analog_id, | ||||
|                     [=, this](const Common::ParamPackage& params) { | ||||
|                         Common::ParamPackage param = system_controller->GetStickParam(analog_id); | ||||
|                         Common::ParamPackage param = emulated_controller->GetStickParam(analog_id); | ||||
|                         SetAnalogParam(params, param, analog_sub_buttons[sub_button_id]); | ||||
|                         // Correct axis direction for inverted sticks | ||||
|                         if (input_subsystem->IsStickInverted(param)) { | ||||
| @@ -552,7 +552,7 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i | ||||
|                                 break; | ||||
|                             } | ||||
|                         } | ||||
|                         system_controller->SetStickParam(analog_id, param); | ||||
|                         emulated_controller->SetStickParam(analog_id, param); | ||||
|                     }, | ||||
|                     InputCommon::Polling::InputType::Stick); | ||||
|             }); | ||||
| @@ -562,10 +562,10 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i | ||||
|             connect(analog_button, &QPushButton::customContextMenuRequested, | ||||
|                     [=, this](const QPoint& menu_location) { | ||||
|                         QMenu context_menu; | ||||
|                         Common::ParamPackage param = system_controller->GetStickParam(analog_id); | ||||
|                         Common::ParamPackage param = emulated_controller->GetStickParam(analog_id); | ||||
|                         context_menu.addAction(tr("Clear"), [&] { | ||||
|                             if (param.Get("engine", "") != "analog_from_button") { | ||||
|                                 system_controller->SetStickParam(analog_id, {}); | ||||
|                                 emulated_controller->SetStickParam(analog_id, {}); | ||||
|                                 for (auto button : analog_map_buttons[analog_id]) { | ||||
|                                     button->setText(tr("[not set]")); | ||||
|                                 } | ||||
| @@ -585,12 +585,12 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i | ||||
|                                 param.Erase("right"); | ||||
|                                 break; | ||||
|                             } | ||||
|                             system_controller->SetStickParam(analog_id, param); | ||||
|                             emulated_controller->SetStickParam(analog_id, param); | ||||
|                             analog_map_buttons[analog_id][sub_button_id]->setText(tr("[not set]")); | ||||
|                         }); | ||||
|                         context_menu.addAction(tr("Center axis"), [&] { | ||||
|                             const auto stick_value = | ||||
|                                 system_controller->GetSticksValues()[analog_id]; | ||||
|                                 emulated_controller->GetSticksValues()[analog_id]; | ||||
|                             const float offset_x = stick_value.x.properties.offset; | ||||
|                             const float offset_y = stick_value.y.properties.offset; | ||||
|                             float raw_value_x = stick_value.x.raw_value; | ||||
| @@ -612,20 +612,20 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i | ||||
|                             } | ||||
|                             param.Set("offset_x", -raw_value_x + offset_x); | ||||
|                             param.Set("offset_y", -raw_value_y + offset_y); | ||||
|                             system_controller->SetStickParam(analog_id, param); | ||||
|                             emulated_controller->SetStickParam(analog_id, param); | ||||
|                         }); | ||||
|                         context_menu.addAction(tr("Invert axis"), [&] { | ||||
|                             if (sub_button_id == 2 || sub_button_id == 3) { | ||||
|                                 const bool invert_value = param.Get("invert_x", "+") == "-"; | ||||
|                                 const std::string invert_str = invert_value ? "+" : "-"; | ||||
|                                 param.Set("invert_x", invert_str); | ||||
|                                 system_controller->SetStickParam(analog_id, param); | ||||
|                                 emulated_controller->SetStickParam(analog_id, param); | ||||
|                             } | ||||
|                             if (sub_button_id == 0 || sub_button_id == 1) { | ||||
|                                 const bool invert_value = param.Get("invert_y", "+") == "-"; | ||||
|                                 const std::string invert_str = invert_value ? "+" : "-"; | ||||
|                                 param.Set("invert_y", invert_str); | ||||
|                                 system_controller->SetStickParam(analog_id, param); | ||||
|                                 emulated_controller->SetStickParam(analog_id, param); | ||||
|                             } | ||||
|                             for (int analog_sub_button_id = 0; | ||||
|                                  analog_sub_button_id < ANALOG_SUB_BUTTONS_NUM; | ||||
| @@ -644,9 +644,9 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i | ||||
|             HandleClick( | ||||
|                 analog_map_modifier_button[analog_id], analog_id, | ||||
|                 [=, this](const Common::ParamPackage& params) { | ||||
|                     Common::ParamPackage param = system_controller->GetStickParam(analog_id); | ||||
|                     Common::ParamPackage param = emulated_controller->GetStickParam(analog_id); | ||||
|                     param.Set("modifier", params.Serialize()); | ||||
|                     system_controller->SetStickParam(analog_id, param); | ||||
|                     emulated_controller->SetStickParam(analog_id, param); | ||||
|                 }, | ||||
|                 InputCommon::Polling::InputType::Button); | ||||
|         }); | ||||
| @@ -657,11 +657,11 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i | ||||
|             analog_map_modifier_button[analog_id], &QPushButton::customContextMenuRequested, | ||||
|             [=, this](const QPoint& menu_location) { | ||||
|                 QMenu context_menu; | ||||
|                 Common::ParamPackage param = system_controller->GetStickParam(analog_id); | ||||
|                 Common::ParamPackage param = emulated_controller->GetStickParam(analog_id); | ||||
|                 context_menu.addAction(tr("Clear"), [&] { | ||||
|                     param.Set("modifier", ""); | ||||
|                     analog_map_modifier_button[analog_id]->setText(tr("[not set]")); | ||||
|                     system_controller->SetStickParam(analog_id, param); | ||||
|                     emulated_controller->SetStickParam(analog_id, param); | ||||
|                 }); | ||||
|                 context_menu.addAction(tr("Toggle button"), [&] { | ||||
|                     Common::ParamPackage modifier_param = | ||||
| @@ -670,7 +670,7 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i | ||||
|                     modifier_param.Set("toggle", toggle_value); | ||||
|                     param.Set("modifier", modifier_param.Serialize()); | ||||
|                     analog_map_modifier_button[analog_id]->setText(ButtonToText(modifier_param)); | ||||
|                     system_controller->SetStickParam(analog_id, param); | ||||
|                     emulated_controller->SetStickParam(analog_id, param); | ||||
|                 }); | ||||
|                 context_menu.addAction(tr("Invert button"), [&] { | ||||
|                     Common::ParamPackage modifier_param = | ||||
| @@ -679,7 +679,7 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i | ||||
|                     modifier_param.Set("inverted", invert_value); | ||||
|                     param.Set("modifier", modifier_param.Serialize()); | ||||
|                     analog_map_modifier_button[analog_id]->setText(ButtonToText(modifier_param)); | ||||
|                     system_controller->SetStickParam(analog_id, param); | ||||
|                     emulated_controller->SetStickParam(analog_id, param); | ||||
|                 }); | ||||
|                 context_menu.exec( | ||||
|                     analog_map_modifier_button[analog_id]->mapToGlobal(menu_location)); | ||||
| @@ -687,27 +687,27 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i | ||||
|  | ||||
|         connect(analog_map_range_spinbox[analog_id], qOverload<int>(&QSpinBox::valueChanged), | ||||
|                 [=, this] { | ||||
|                     Common::ParamPackage param = system_controller->GetStickParam(analog_id); | ||||
|                     Common::ParamPackage param = emulated_controller->GetStickParam(analog_id); | ||||
|                     const auto spinbox_value = analog_map_range_spinbox[analog_id]->value(); | ||||
|                     param.Set("range", spinbox_value / 100.0f); | ||||
|                     system_controller->SetStickParam(analog_id, param); | ||||
|                     emulated_controller->SetStickParam(analog_id, param); | ||||
|                 }); | ||||
|  | ||||
|         connect(analog_map_deadzone_slider[analog_id], &QSlider::valueChanged, [=, this] { | ||||
|             Common::ParamPackage param = system_controller->GetStickParam(analog_id); | ||||
|             Common::ParamPackage param = emulated_controller->GetStickParam(analog_id); | ||||
|             const auto slider_value = analog_map_deadzone_slider[analog_id]->value(); | ||||
|             analog_map_deadzone_label[analog_id]->setText(tr("Deadzone: %1%").arg(slider_value)); | ||||
|             param.Set("deadzone", slider_value / 100.0f); | ||||
|             system_controller->SetStickParam(analog_id, param); | ||||
|             emulated_controller->SetStickParam(analog_id, param); | ||||
|         }); | ||||
|  | ||||
|         connect(analog_map_modifier_slider[analog_id], &QSlider::valueChanged, [=, this] { | ||||
|             Common::ParamPackage param = system_controller->GetStickParam(analog_id); | ||||
|             Common::ParamPackage param = emulated_controller->GetStickParam(analog_id); | ||||
|             const auto slider_value = analog_map_modifier_slider[analog_id]->value(); | ||||
|             analog_map_modifier_label[analog_id]->setText( | ||||
|                 tr("Modifier Range: %1%").arg(slider_value)); | ||||
|             param.Set("modifier_scale", slider_value / 100.0f); | ||||
|             system_controller->SetStickParam(analog_id, param); | ||||
|             emulated_controller->SetStickParam(analog_id, param); | ||||
|         }); | ||||
|     } | ||||
|  | ||||
| @@ -749,28 +749,28 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i | ||||
|             GetControllerTypeFromIndex(ui->comboControllerType->currentIndex()); | ||||
|  | ||||
|         if (player_index == 0) { | ||||
|             auto* system_controller_p1 = | ||||
|                 hid_core.GetSystemController(Core::HID::NpadIdType::Player1); | ||||
|             auto* system_controller_handheld = | ||||
|                 hid_core.GetSystemController(Core::HID::NpadIdType::Handheld); | ||||
|             bool is_connected = system_controller->IsConnected(true); | ||||
|             auto* emulated_controller_p1 = | ||||
|                 hid_core.GetEmulatedController(Core::HID::NpadIdType::Player1); | ||||
|             auto* emulated_controller_handheld = | ||||
|                 hid_core.GetEmulatedController(Core::HID::NpadIdType::Handheld); | ||||
|             bool is_connected = emulated_controller->IsConnected(true); | ||||
|  | ||||
|             system_controller_p1->SetNpadStyleIndex(type); | ||||
|             system_controller_handheld->SetNpadStyleIndex(type); | ||||
|             emulated_controller_p1->SetNpadStyleIndex(type); | ||||
|             emulated_controller_handheld->SetNpadStyleIndex(type); | ||||
|             if (is_connected) { | ||||
|                 if (type == Core::HID::NpadStyleIndex::Handheld) { | ||||
|                     system_controller_p1->Disconnect(); | ||||
|                     system_controller_handheld->Connect(true); | ||||
|                     system_controller = system_controller_handheld; | ||||
|                     emulated_controller_p1->Disconnect(); | ||||
|                     emulated_controller_handheld->Connect(true); | ||||
|                     emulated_controller = emulated_controller_handheld; | ||||
|                 } else { | ||||
|                     system_controller_handheld->Disconnect(); | ||||
|                     system_controller_p1->Connect(true); | ||||
|                     system_controller = system_controller_p1; | ||||
|                     emulated_controller_handheld->Disconnect(); | ||||
|                     emulated_controller_p1->Connect(true); | ||||
|                     emulated_controller = emulated_controller_p1; | ||||
|                 } | ||||
|             } | ||||
|             ui->controllerFrame->SetController(system_controller->GetNpadIdType()); | ||||
|             ui->controllerFrame->SetController(emulated_controller); | ||||
|         } | ||||
|         system_controller->SetNpadStyleIndex(type); | ||||
|         emulated_controller->SetNpadStyleIndex(type); | ||||
|     }); | ||||
|  | ||||
|     connect(ui->comboDevices, qOverload<int>(&QComboBox::activated), this, | ||||
| @@ -806,33 +806,34 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i | ||||
|  | ||||
| ConfigureInputPlayer::~ConfigureInputPlayer() { | ||||
|     if (player_index == 0) { | ||||
|         auto* system_controller_p1 = | ||||
|             hid_core.GetSystemController(Core::HID::NpadIdType::Player1); | ||||
|         auto* system_controller_handheld = | ||||
|             hid_core.GetSystemController(Core::HID::NpadIdType::Handheld); | ||||
|         system_controller_p1->DisableConfiguration(); | ||||
|         system_controller_handheld->DisableConfiguration(); | ||||
|         auto* emulated_controller_p1 = | ||||
|             hid_core.GetEmulatedController(Core::HID::NpadIdType::Player1); | ||||
|         auto* emulated_controller_handheld = | ||||
|             hid_core.GetEmulatedController(Core::HID::NpadIdType::Handheld); | ||||
|         emulated_controller_p1->DisableConfiguration(); | ||||
|         emulated_controller_handheld->DisableConfiguration(); | ||||
|     } else { | ||||
|         system_controller->DisableConfiguration(); | ||||
|         emulated_controller->DisableConfiguration(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void ConfigureInputPlayer::ApplyConfiguration() { | ||||
|     if (player_index == 0) { | ||||
|         auto* system_controller_p1 = hid_core.GetSystemController(Core::HID::NpadIdType::Player1); | ||||
|         auto* system_controller_handheld = | ||||
|             hid_core.GetSystemController(Core::HID::NpadIdType::Handheld); | ||||
|         system_controller_p1->DisableConfiguration(); | ||||
|         system_controller_p1->SaveCurrentConfig(); | ||||
|         system_controller_p1->EnableConfiguration(); | ||||
|         system_controller_handheld->DisableConfiguration(); | ||||
|         system_controller_handheld->SaveCurrentConfig(); | ||||
|         system_controller_handheld->EnableConfiguration(); | ||||
|         auto* emulated_controller_p1 = | ||||
|             hid_core.GetEmulatedController(Core::HID::NpadIdType::Player1); | ||||
|         auto* emulated_controller_handheld = | ||||
|             hid_core.GetEmulatedController(Core::HID::NpadIdType::Handheld); | ||||
|         emulated_controller_p1->DisableConfiguration(); | ||||
|         emulated_controller_p1->SaveCurrentConfig(); | ||||
|         emulated_controller_p1->EnableConfiguration(); | ||||
|         emulated_controller_handheld->DisableConfiguration(); | ||||
|         emulated_controller_handheld->SaveCurrentConfig(); | ||||
|         emulated_controller_handheld->EnableConfiguration(); | ||||
|         return; | ||||
|     } | ||||
|     system_controller->DisableConfiguration(); | ||||
|     system_controller->SaveCurrentConfig(); | ||||
|     system_controller->EnableConfiguration(); | ||||
|     emulated_controller->DisableConfiguration(); | ||||
|     emulated_controller->SaveCurrentConfig(); | ||||
|     emulated_controller->EnableConfiguration(); | ||||
| } | ||||
|  | ||||
| void ConfigureInputPlayer::showEvent(QShowEvent* event) { | ||||
| @@ -857,7 +858,7 @@ void ConfigureInputPlayer::RetranslateUI() { | ||||
| } | ||||
|  | ||||
| void ConfigureInputPlayer::LoadConfiguration() { | ||||
|     system_controller->ReloadFromSettings(); | ||||
|     emulated_controller->ReloadFromSettings(); | ||||
|  | ||||
|     UpdateUI(); | ||||
|     UpdateInputDeviceCombobox(); | ||||
| @@ -867,17 +868,17 @@ void ConfigureInputPlayer::LoadConfiguration() { | ||||
|     } | ||||
|  | ||||
|     const int comboBoxIndex = | ||||
|         GetIndexFromControllerType(system_controller->GetNpadStyleIndex(true)); | ||||
|         GetIndexFromControllerType(emulated_controller->GetNpadStyleIndex(true)); | ||||
|     ui->comboControllerType->setCurrentIndex(comboBoxIndex); | ||||
|     ui->groupConnectedController->setChecked(system_controller->IsConnected(true)); | ||||
|     ui->groupConnectedController->setChecked(emulated_controller->IsConnected(true)); | ||||
| } | ||||
|  | ||||
| void ConfigureInputPlayer::ConnectPlayer(bool connected) { | ||||
|     ui->groupConnectedController->setChecked(connected); | ||||
|     if (connected) { | ||||
|         system_controller->Connect(true); | ||||
|         emulated_controller->Connect(true); | ||||
|     } else { | ||||
|         system_controller->Disconnect(); | ||||
|         emulated_controller->Disconnect(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -888,7 +889,7 @@ void ConfigureInputPlayer::UpdateInputDeviceCombobox() { | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     const auto devices = system_controller->GetMappedDevices(); | ||||
|     const auto devices = emulated_controller->GetMappedDevices(); | ||||
|     UpdateInputDevices(); | ||||
|  | ||||
|     if (devices.empty()) { | ||||
| @@ -967,7 +968,7 @@ void ConfigureInputPlayer::ClearAll() { | ||||
|         if (button == nullptr) { | ||||
|             continue; | ||||
|         } | ||||
|         system_controller->SetButtonParam(button_id, {}); | ||||
|         emulated_controller->SetButtonParam(button_id, {}); | ||||
|     } | ||||
|  | ||||
|     for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; ++analog_id) { | ||||
| @@ -976,7 +977,7 @@ void ConfigureInputPlayer::ClearAll() { | ||||
|             if (analog_button == nullptr) { | ||||
|                 continue; | ||||
|             } | ||||
|             system_controller->SetStickParam(analog_id, {}); | ||||
|             emulated_controller->SetStickParam(analog_id, {}); | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @@ -985,7 +986,7 @@ void ConfigureInputPlayer::ClearAll() { | ||||
|         if (motion_button == nullptr) { | ||||
|             continue; | ||||
|         } | ||||
|         system_controller->SetMotionParam(motion_id, {}); | ||||
|         emulated_controller->SetMotionParam(motion_id, {}); | ||||
|     } | ||||
|  | ||||
|     UpdateUI(); | ||||
| @@ -994,31 +995,31 @@ void ConfigureInputPlayer::ClearAll() { | ||||
|  | ||||
| void ConfigureInputPlayer::UpdateUI() { | ||||
|     for (int button = 0; button < Settings::NativeButton::NumButtons; ++button) { | ||||
|         const Common::ParamPackage param = system_controller->GetButtonParam(button); | ||||
|         const Common::ParamPackage param = emulated_controller->GetButtonParam(button); | ||||
|         button_map[button]->setText(ButtonToText(param)); | ||||
|     } | ||||
|  | ||||
|     const Common::ParamPackage ZL_param = | ||||
|         system_controller->GetButtonParam(Settings::NativeButton::ZL); | ||||
|         emulated_controller->GetButtonParam(Settings::NativeButton::ZL); | ||||
|     if (ZL_param.Has("threshold")) { | ||||
|         const int button_threshold = static_cast<int>(ZL_param.Get("threshold", 0.5f) * 100.0f); | ||||
|         ui->sliderZLThreshold->setValue(button_threshold); | ||||
|     } | ||||
|  | ||||
|     const Common::ParamPackage ZR_param = | ||||
|         system_controller->GetButtonParam(Settings::NativeButton::ZR); | ||||
|         emulated_controller->GetButtonParam(Settings::NativeButton::ZR); | ||||
|     if (ZR_param.Has("threshold")) { | ||||
|         const int button_threshold = static_cast<int>(ZR_param.Get("threshold", 0.5f) * 100.0f); | ||||
|         ui->sliderZRThreshold->setValue(button_threshold); | ||||
|     } | ||||
|  | ||||
|     for (int motion_id = 0; motion_id < Settings::NativeMotion::NumMotions; ++motion_id) { | ||||
|         const Common::ParamPackage param = system_controller->GetMotionParam(motion_id); | ||||
|         const Common::ParamPackage param = emulated_controller->GetMotionParam(motion_id); | ||||
|         motion_map[motion_id]->setText(ButtonToText(param)); | ||||
|     } | ||||
|  | ||||
|     for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; ++analog_id) { | ||||
|         const Common::ParamPackage param = system_controller->GetStickParam(analog_id); | ||||
|         const Common::ParamPackage param = emulated_controller->GetStickParam(analog_id); | ||||
|         for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; ++sub_button_id) { | ||||
|             auto* const analog_button = analog_map_buttons[analog_id][sub_button_id]; | ||||
|  | ||||
| @@ -1346,7 +1347,7 @@ void ConfigureInputPlayer::UpdateMappingWithDefaults() { | ||||
|         if (button == nullptr) { | ||||
|             continue; | ||||
|         } | ||||
|         system_controller->SetButtonParam(button_id, {}); | ||||
|         emulated_controller->SetButtonParam(button_id, {}); | ||||
|     } | ||||
|  | ||||
|     for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; ++analog_id) { | ||||
| @@ -1355,7 +1356,7 @@ void ConfigureInputPlayer::UpdateMappingWithDefaults() { | ||||
|             if (analog_button == nullptr) { | ||||
|                 continue; | ||||
|             } | ||||
|             system_controller->SetStickParam(analog_id, {}); | ||||
|             emulated_controller->SetStickParam(analog_id, {}); | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @@ -1364,13 +1365,13 @@ void ConfigureInputPlayer::UpdateMappingWithDefaults() { | ||||
|         if (motion_button == nullptr) { | ||||
|             continue; | ||||
|         } | ||||
|         system_controller->SetMotionParam(motion_id, {}); | ||||
|         emulated_controller->SetMotionParam(motion_id, {}); | ||||
|     } | ||||
|  | ||||
|     // Reset keyboard or mouse bindings | ||||
|     if (ui->comboDevices->currentIndex() == 1 || ui->comboDevices->currentIndex() == 2) { | ||||
|         for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; ++button_id) { | ||||
|             system_controller->SetButtonParam( | ||||
|             emulated_controller->SetButtonParam( | ||||
|                 button_id, Common::ParamPackage{InputCommon::GenerateKeyboardParam( | ||||
|                                Config::default_buttons[button_id])}); | ||||
|         } | ||||
| @@ -1384,11 +1385,11 @@ void ConfigureInputPlayer::UpdateMappingWithDefaults() { | ||||
|  | ||||
|             analog_param.Set("modifier", InputCommon::GenerateKeyboardParam( | ||||
|                                              Config::default_stick_mod[analog_id])); | ||||
|             system_controller->SetStickParam(analog_id, analog_param); | ||||
|             emulated_controller->SetStickParam(analog_id, analog_param); | ||||
|         } | ||||
|  | ||||
|         for (int motion_id = 0; motion_id < Settings::NativeMotion::NumMotions; ++motion_id) { | ||||
|             system_controller->SetMotionParam( | ||||
|             emulated_controller->SetMotionParam( | ||||
|                 motion_id, Common::ParamPackage{InputCommon::GenerateKeyboardParam( | ||||
|                                Config::default_motions[motion_id])}); | ||||
|         } | ||||
| @@ -1408,15 +1409,15 @@ void ConfigureInputPlayer::UpdateMappingWithDefaults() { | ||||
|  | ||||
|     for (const auto& button_mapping : button_mappings) { | ||||
|         const std::size_t index = button_mapping.first; | ||||
|         system_controller->SetButtonParam(index, button_mapping.second); | ||||
|         emulated_controller->SetButtonParam(index, button_mapping.second); | ||||
|     } | ||||
|     for (const auto& analog_mapping : analog_mappings) { | ||||
|         const std::size_t index = analog_mapping.first; | ||||
|         system_controller->SetStickParam(index, analog_mapping.second); | ||||
|         emulated_controller->SetStickParam(index, analog_mapping.second); | ||||
|     } | ||||
|     for (const auto& motion_mapping : motion_mappings) { | ||||
|         const std::size_t index = motion_mapping.first; | ||||
|         system_controller->SetMotionParam(index, motion_mapping.second); | ||||
|         emulated_controller->SetMotionParam(index, motion_mapping.second); | ||||
|     } | ||||
|  | ||||
|     UpdateUI(); | ||||
| @@ -1608,7 +1609,7 @@ void ConfigureInputPlayer::SaveProfile() { | ||||
|     ApplyConfiguration(); | ||||
|  | ||||
|     // When we're in handheld mode, only the handheld emulated controller bindings are updated | ||||
|     const bool is_handheld = player_index == 0 && system_controller->GetNpadIdType() == | ||||
|     const bool is_handheld = player_index == 0 && emulated_controller->GetNpadIdType() == | ||||
|                                                       Core::HID::NpadIdType::Handheld; | ||||
|     const auto profile_player_index = is_handheld ? HANDHELD_INDEX : player_index; | ||||
|  | ||||
|   | ||||
| @@ -42,7 +42,7 @@ class ConfigureInputPlayer; | ||||
|  | ||||
| namespace Core::HID { | ||||
| class HIDCore; | ||||
| class SystemController; | ||||
| class EmulatedController; | ||||
| enum class NpadStyleIndex : u8; | ||||
| } // namespace Core::HID | ||||
|  | ||||
| @@ -189,7 +189,7 @@ private: | ||||
|     /// This will be the the setting function when an input is awaiting configuration. | ||||
|     std::optional<std::function<void(const Common::ParamPackage&)>> input_setter; | ||||
|  | ||||
|     Core::HID::SystemController* system_controller; | ||||
|     Core::HID::EmulatedController* emulated_controller; | ||||
|  | ||||
|     static constexpr int ANALOG_SUB_BUTTONS_NUM = 4; | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user