diff --git a/Source/Core/Core/HW/GCPadEmu.cpp b/Source/Core/Core/HW/GCPadEmu.cpp index 22c416c7b9..f8f8c47d54 100644 --- a/Source/Core/Core/HW/GCPadEmu.cpp +++ b/Source/Core/Core/HW/GCPadEmu.cpp @@ -83,6 +83,10 @@ GCPad::GCPad(const unsigned int index) : m_index(index) // options groups.emplace_back(m_options = new ControllerEmu::ControlGroup(_trans("Options"))); + m_options->boolean_settings.emplace_back( + // i18n: Treat a controller as always being connected regardless of what + // devices the user actually has plugged in + m_always_connected = new ControllerEmu::BooleanSetting(_trans("Always Connected"), false)); m_options->boolean_settings.emplace_back(std::make_unique( _trans("Iterative Input"), false, ControllerEmu::SettingType::VIRTUAL)); } @@ -124,6 +128,12 @@ GCPadStatus GCPad::GetInput() const ControlState x, y, triggers[2]; GCPadStatus pad = {}; + if (!(m_always_connected->GetValue() || IsDefaultDeviceConnected())) + { + pad.isConnected = false; + return pad; + } + // buttons m_buttons->GetState(&pad.button, button_bitmasks); diff --git a/Source/Core/Core/HW/GCPadEmu.h b/Source/Core/Core/HW/GCPadEmu.h index ad3f3a48a2..c5a10acfa6 100644 --- a/Source/Core/Core/HW/GCPadEmu.h +++ b/Source/Core/Core/HW/GCPadEmu.h @@ -6,6 +6,7 @@ #include +#include "InputCommon/ControllerEmu/ControlGroup/ControlGroup.h" #include "InputCommon/ControllerEmu/ControllerEmu.h" struct GCPadStatus; @@ -14,7 +15,6 @@ namespace ControllerEmu { class AnalogStick; class Buttons; -class ControlGroup; class MixedTriggers; } @@ -54,6 +54,7 @@ private: ControllerEmu::ControlGroup* m_rumble; ControllerEmu::Buttons* m_mic; ControllerEmu::ControlGroup* m_options; + ControllerEmu::BooleanSetting* m_always_connected; const unsigned int m_index; diff --git a/Source/Core/Core/HW/SI/SI_DeviceGCController.cpp b/Source/Core/Core/HW/SI/SI_DeviceGCController.cpp index d921ea2937..5d1ccacfb5 100644 --- a/Source/Core/Core/HW/SI/SI_DeviceGCController.cpp +++ b/Source/Core/Core/HW/SI/SI_DeviceGCController.cpp @@ -47,6 +47,14 @@ int CSIDevice_GCController::RunBuffer(u8* buffer, int length) // For debug logging only ISIDevice::RunBuffer(buffer, length); + GCPadStatus pad_status = GetPadStatus(); + if (!pad_status.isConnected) + { + constexpr u32 reply = SI_ERROR_NO_RESPONSE; + std::memcpy(buffer, &reply, sizeof(reply)); + return 4; + } + // Read the command EBufferCommands command = static_cast(buffer[3]); @@ -165,6 +173,13 @@ GCPadStatus CSIDevice_GCController::GetPadStatus() bool CSIDevice_GCController::GetData(u32& hi, u32& low) { GCPadStatus pad_status = GetPadStatus(); + + if (!pad_status.isConnected) + { + hi = 0x80000000; + return true; + } + if (HandleButtonCombos(pad_status) == COMBO_ORIGIN) pad_status.button |= PAD_GET_ORIGIN; diff --git a/Source/Core/InputCommon/ControllerEmu/ControllerEmu.cpp b/Source/Core/InputCommon/ControllerEmu/ControllerEmu.cpp index cf70fa8468..98b9e5828b 100644 --- a/Source/Core/InputCommon/ControllerEmu/ControllerEmu.cpp +++ b/Source/Core/InputCommon/ControllerEmu/ControllerEmu.cpp @@ -34,6 +34,8 @@ std::unique_lock EmulatedController::GetStateLock() void EmulatedController::UpdateReferences(const ControllerInterface& devi) { const auto lock = GetStateLock(); + m_default_device_is_connected = devi.HasConnectedDevice(m_default_device); + for (auto& ctrlGroup : groups) { for (auto& control : ctrlGroup->controls) @@ -48,6 +50,11 @@ void EmulatedController::UpdateReferences(const ControllerInterface& devi) } } +bool EmulatedController::IsDefaultDeviceConnected() const +{ + return m_default_device_is_connected; +} + const ciface::Core::DeviceQualifier& EmulatedController::GetDefaultDevice() const { return m_default_device; diff --git a/Source/Core/InputCommon/ControllerEmu/ControllerEmu.h b/Source/Core/InputCommon/ControllerEmu/ControllerEmu.h index c9faf4457c..8b7925f7df 100644 --- a/Source/Core/InputCommon/ControllerEmu/ControllerEmu.h +++ b/Source/Core/InputCommon/ControllerEmu/ControllerEmu.h @@ -33,6 +33,7 @@ public: virtual void LoadConfig(IniFile::Section* sec, const std::string& base = ""); virtual void SaveConfig(IniFile::Section* sec, const std::string& base = ""); + bool IsDefaultDeviceConnected() const; const ciface::Core::DeviceQualifier& GetDefaultDevice() const; void SetDefaultDevice(const std::string& device); void SetDefaultDevice(ciface::Core::DeviceQualifier devq); @@ -49,5 +50,6 @@ public: private: ciface::Core::DeviceQualifier m_default_device; + bool m_default_device_is_connected{false}; }; } // namespace ControllerEmu diff --git a/Source/Core/InputCommon/ControllerInterface/Device.cpp b/Source/Core/InputCommon/ControllerInterface/Device.cpp index f83dae268e..48d40cb9af 100644 --- a/Source/Core/InputCommon/ControllerInterface/Device.cpp +++ b/Source/Core/InputCommon/ControllerInterface/Device.cpp @@ -199,5 +199,11 @@ Device::Output* DeviceContainer::FindOutput(const std::string& name, const Devic { return def_dev->FindOutput(name); } + +bool DeviceContainer::HasConnectedDevice(const DeviceQualifier& qualifier) const +{ + const auto device = FindDevice(qualifier); + return device != nullptr && device->IsValid(); +} } } diff --git a/Source/Core/InputCommon/ControllerInterface/Device.h b/Source/Core/InputCommon/ControllerInterface/Device.h index 7b601cc775..5482b93ac0 100644 --- a/Source/Core/InputCommon/ControllerInterface/Device.h +++ b/Source/Core/InputCommon/ControllerInterface/Device.h @@ -158,6 +158,8 @@ public: std::string GetDefaultDeviceString() const; std::shared_ptr FindDevice(const DeviceQualifier& devq) const; + bool HasConnectedDevice(const DeviceQualifier& qualifier) const; + protected: mutable std::mutex m_devices_mutex; std::vector> m_devices;