From bb1c7946572163d461f2fec0ca4889e3cd35b750 Mon Sep 17 00:00:00 2001 From: Michael Maltese Date: Thu, 9 Feb 2017 14:49:20 -0800 Subject: [PATCH 1/3] Remove unused GCPadStatus.err --- Source/Core/Core/HotkeyManager.cpp | 2 -- Source/Core/Core/Movie.cpp | 6 ------ Source/Core/InputCommon/GCPadStatus.h | 9 --------- 3 files changed, 17 deletions(-) diff --git a/Source/Core/Core/HotkeyManager.cpp b/Source/Core/Core/HotkeyManager.cpp index d989627ad1..6e96aad1d7 100644 --- a/Source/Core/Core/HotkeyManager.cpp +++ b/Source/Core/Core/HotkeyManager.cpp @@ -174,8 +174,6 @@ InputConfig* GetConfig() void GetStatus() { - s_hotkey.err = PAD_ERR_NONE; - // Get input static_cast(s_config.GetController(0))->GetInput(&s_hotkey); } diff --git a/Source/Core/Core/Movie.cpp b/Source/Core/Core/Movie.cpp index 75bf23ee43..9ee7d2e818 100644 --- a/Source/Core/Core/Movie.cpp +++ b/Source/Core/Core/Movie.cpp @@ -1110,12 +1110,6 @@ void PlayController(GCPadStatus* PadStatus, int controllerID) return; } - // dtm files don't save the mic button or error bit. not sure if they're actually used, but better - // safe than sorry - signed char e = PadStatus->err; - memset(PadStatus, 0, sizeof(GCPadStatus)); - PadStatus->err = e; - memcpy(&s_padState, &s_temp_input[s_currentByte], sizeof(ControllerState)); s_currentByte += sizeof(ControllerState); diff --git a/Source/Core/InputCommon/GCPadStatus.h b/Source/Core/InputCommon/GCPadStatus.h index d9aa6c5a91..42784ca6e1 100644 --- a/Source/Core/InputCommon/GCPadStatus.h +++ b/Source/Core/InputCommon/GCPadStatus.h @@ -6,14 +6,6 @@ #include "Common/CommonTypes.h" -enum PadError -{ - PAD_ERR_NONE = 0, - PAD_ERR_NO_CONTROLLER = -1, - PAD_ERR_NOT_READY = -2, - PAD_ERR_TRANSFER = -3, -}; - enum { PAD_USE_ORIGIN = 0x0080, @@ -48,7 +40,6 @@ struct GCPadStatus u8 triggerRight; // 0 <= triggerRight <= 255 u8 analogA; // 0 <= analogA <= 255 u8 analogB; // 0 <= analogB <= 255 - s8 err; // one of PAD_ERR_* number static const u8 MAIN_STICK_CENTER_X = 0x80; static const u8 MAIN_STICK_CENTER_Y = 0x80; From 379e28b58ca335443e398692f0f22e36f5040761 Mon Sep 17 00:00:00 2001 From: Michael Maltese Date: Thu, 9 Feb 2017 15:03:43 -0800 Subject: [PATCH 2/3] Add GCPadStatus.isConnected boolean --- Source/Core/Core/Movie.cpp | 82 +++++++++++++++------------ Source/Core/Core/Movie.h | 9 +-- Source/Core/Core/NetPlayClient.cpp | 4 +- Source/Core/Core/NetPlayServer.cpp | 5 +- Source/Core/InputCommon/GCPadStatus.h | 1 + 5 files changed, 58 insertions(+), 43 deletions(-) diff --git a/Source/Core/Core/Movie.cpp b/Source/Core/Core/Movie.cpp index 9ee7d2e818..58247a60e6 100644 --- a/Source/Core/Core/Movie.cpp +++ b/Source/Core/Core/Movie.cpp @@ -601,34 +601,41 @@ static void SetInputDisplayString(ControllerState padState, int controllerID) { std::string display_str = StringFromFormat("P%d:", controllerID + 1); - if (padState.A) - display_str += " A"; - if (padState.B) - display_str += " B"; - if (padState.X) - display_str += " X"; - if (padState.Y) - display_str += " Y"; - if (padState.Z) - display_str += " Z"; - if (padState.Start) - display_str += " START"; + if (padState.is_connected) + { + if (padState.A) + display_str += " A"; + if (padState.B) + display_str += " B"; + if (padState.X) + display_str += " X"; + if (padState.Y) + display_str += " Y"; + if (padState.Z) + display_str += " Z"; + if (padState.Start) + display_str += " START"; - if (padState.DPadUp) - display_str += " UP"; - if (padState.DPadDown) - display_str += " DOWN"; - if (padState.DPadLeft) - display_str += " LEFT"; - if (padState.DPadRight) - display_str += " RIGHT"; - if (padState.reset) - display_str += " RESET"; + if (padState.DPadUp) + display_str += " UP"; + if (padState.DPadDown) + display_str += " DOWN"; + if (padState.DPadLeft) + display_str += " LEFT"; + if (padState.DPadRight) + display_str += " RIGHT"; + if (padState.reset) + display_str += " RESET"; - display_str += Analog1DToString(padState.TriggerL, " L"); - display_str += Analog1DToString(padState.TriggerR, " R"); - display_str += Analog2DToString(padState.AnalogStickX, padState.AnalogStickY, " ANA"); - display_str += Analog2DToString(padState.CStickX, padState.CStickY, " C"); + display_str += Analog1DToString(padState.TriggerL, " L"); + display_str += Analog1DToString(padState.TriggerR, " R"); + display_str += Analog2DToString(padState.AnalogStickX, padState.AnalogStickY, " ANA"); + display_str += Analog2DToString(padState.CStickX, padState.CStickY, " C"); + } + else + { + display_str += " DISCONNECTED"; + } std::lock_guard guard(s_input_display_lock); s_InputDisplay[controllerID] = std::move(display_str); @@ -782,6 +789,8 @@ void CheckPadStatus(GCPadStatus* PadStatus, int controllerID) s_padState.CStickX = PadStatus->substickX; s_padState.CStickY = PadStatus->substickY; + s_padState.is_connected = PadStatus->isConnected; + s_padState.disc = s_bDiscChange; s_bDiscChange = false; s_padState.reset = s_bReset; @@ -1031,24 +1040,25 @@ void LoadInput(const std::string& filename) "is %d frames long.\n\n" "On frame %td, the current movie presses:\n" "Start=%d, A=%d, B=%d, X=%d, Y=%d, Z=%d, DUp=%d, DDown=%d, DLeft=%d, DRight=%d, " - "L=%d, R=%d, LT=%d, RT=%d, AnalogX=%d, AnalogY=%d, CX=%d, CY=%d" + "L=%d, R=%d, LT=%d, RT=%d, AnalogX=%d, AnalogY=%d, CX=%d, CY=%d, Connected=%d" "\n\n" "On frame %td, the savestate's movie presses:\n" "Start=%d, A=%d, B=%d, X=%d, Y=%d, Z=%d, DUp=%d, DDown=%d, DLeft=%d, DRight=%d, " - "L=%d, R=%d, LT=%d, RT=%d, AnalogX=%d, AnalogY=%d, CX=%d, CY=%d", + "L=%d, R=%d, LT=%d, RT=%d, AnalogX=%d, AnalogY=%d, CX=%d, CY=%d, Connected=%d", frame, (int)s_totalFrames, (int)tmpHeader.frameCount, frame, (int)curPadState.Start, (int)curPadState.A, (int)curPadState.B, (int)curPadState.X, (int)curPadState.Y, (int)curPadState.Z, (int)curPadState.DPadUp, (int)curPadState.DPadDown, (int)curPadState.DPadLeft, (int)curPadState.DPadRight, (int)curPadState.L, (int)curPadState.R, (int)curPadState.TriggerL, (int)curPadState.TriggerR, (int)curPadState.AnalogStickX, (int)curPadState.AnalogStickY, - (int)curPadState.CStickX, (int)curPadState.CStickY, frame, (int)movPadState.Start, - (int)movPadState.A, (int)movPadState.B, (int)movPadState.X, (int)movPadState.Y, - (int)movPadState.Z, (int)movPadState.DPadUp, (int)movPadState.DPadDown, - (int)movPadState.DPadLeft, (int)movPadState.DPadRight, (int)movPadState.L, - (int)movPadState.R, (int)movPadState.TriggerL, (int)movPadState.TriggerR, - (int)movPadState.AnalogStickX, (int)movPadState.AnalogStickY, - (int)movPadState.CStickX, (int)movPadState.CStickY); + (int)curPadState.CStickX, (int)curPadState.CStickY, (int)curPadState.is_connected, + frame, (int)movPadState.Start, (int)movPadState.A, (int)movPadState.B, + (int)movPadState.X, (int)movPadState.Y, (int)movPadState.Z, (int)movPadState.DPadUp, + (int)movPadState.DPadDown, (int)movPadState.DPadLeft, (int)movPadState.DPadRight, + (int)movPadState.L, (int)movPadState.R, (int)movPadState.TriggerL, + (int)movPadState.TriggerR, (int)movPadState.AnalogStickX, + (int)movPadState.AnalogStickY, (int)movPadState.CStickX, (int)movPadState.CStickY, + (int)curPadState.is_connected); } } } @@ -1113,6 +1123,8 @@ void PlayController(GCPadStatus* PadStatus, int controllerID) memcpy(&s_padState, &s_temp_input[s_currentByte], sizeof(ControllerState)); s_currentByte += sizeof(ControllerState); + PadStatus->isConnected = s_padState.is_connected; + PadStatus->triggerLeft = s_padState.TriggerL; PadStatus->triggerRight = s_padState.TriggerR; diff --git a/Source/Core/Core/Movie.h b/Source/Core/Core/Movie.h index e369c5891a..7500fc7456 100644 --- a/Source/Core/Core/Movie.h +++ b/Source/Core/Core/Movie.h @@ -39,10 +39,11 @@ struct ControllerState bool Start : 1, A : 1, B : 1, X : 1, Y : 1, Z : 1; // Binary buttons, 6 bits bool DPadUp : 1, DPadDown : 1, // Binary D-Pad buttons, 4 bits DPadLeft : 1, DPadRight : 1; - bool L : 1, R : 1; // Binary triggers, 2 bits - bool disc : 1; // Checks for disc being changed - bool reset : 1; // Console reset button - bool reserved : 2; // Reserved bits used for padding, 2 bits + bool L : 1, R : 1; // Binary triggers, 2 bits + bool disc : 1; // Checks for disc being changed + bool reset : 1; // Console reset button + bool is_connected : 1; // Should controller be treated as connected + bool reserved : 1; // Reserved bits used for padding, 1 bit u8 TriggerL, TriggerR; // Triggers, 16 bits u8 AnalogStickX, AnalogStickY; // Main Stick, 16 bits diff --git a/Source/Core/Core/NetPlayClient.cpp b/Source/Core/Core/NetPlayClient.cpp index adf68c44b0..465da26370 100644 --- a/Source/Core/Core/NetPlayClient.cpp +++ b/Source/Core/Core/NetPlayClient.cpp @@ -326,7 +326,7 @@ unsigned int NetPlayClient::OnData(sf::Packet& packet) PadMapping map = 0; GCPadStatus pad; packet >> map >> pad.button >> pad.analogA >> pad.analogB >> pad.stickX >> pad.stickY >> - pad.substickX >> pad.substickY >> pad.triggerLeft >> pad.triggerRight; + pad.substickX >> pad.substickY >> pad.triggerLeft >> pad.triggerRight >> pad.isConnected; // Trusting server for good map value (>=0 && <4) // add to pad buffer @@ -753,7 +753,7 @@ void NetPlayClient::SendPadState(const int in_game_pad, const GCPadStatus& pad) packet << static_cast(NP_MSG_PAD_DATA); packet << static_cast(in_game_pad); packet << pad.button << pad.analogA << pad.analogB << pad.stickX << pad.stickY << pad.substickX - << pad.substickY << pad.triggerLeft << pad.triggerRight; + << pad.substickY << pad.triggerLeft << pad.triggerRight << pad.isConnected; SendAsync(std::move(packet)); } diff --git a/Source/Core/Core/NetPlayServer.cpp b/Source/Core/Core/NetPlayServer.cpp index cf36644c22..595c246ec1 100644 --- a/Source/Core/Core/NetPlayServer.cpp +++ b/Source/Core/Core/NetPlayServer.cpp @@ -520,7 +520,7 @@ unsigned int NetPlayServer::OnData(sf::Packet& packet, Client& player) PadMapping map = 0; GCPadStatus pad; packet >> map >> pad.button >> pad.analogA >> pad.analogB >> pad.stickX >> pad.stickY >> - pad.substickX >> pad.substickY >> pad.triggerLeft >> pad.triggerRight; + pad.substickX >> pad.substickY >> pad.triggerLeft >> pad.triggerRight >> pad.isConnected; // If the data is not from the correct player, // then disconnect them. @@ -533,7 +533,8 @@ unsigned int NetPlayServer::OnData(sf::Packet& packet, Client& player) sf::Packet spac; spac << (MessageId)NP_MSG_PAD_DATA; spac << map << pad.button << pad.analogA << pad.analogB << pad.stickX << pad.stickY - << pad.substickX << pad.substickY << pad.triggerLeft << pad.triggerRight; + << pad.substickX << pad.substickY << pad.triggerLeft << pad.triggerRight + << pad.isConnected; SendToClients(spac, player.pid); } diff --git a/Source/Core/InputCommon/GCPadStatus.h b/Source/Core/InputCommon/GCPadStatus.h index 42784ca6e1..7da1bbd4fc 100644 --- a/Source/Core/InputCommon/GCPadStatus.h +++ b/Source/Core/InputCommon/GCPadStatus.h @@ -40,6 +40,7 @@ struct GCPadStatus u8 triggerRight; // 0 <= triggerRight <= 255 u8 analogA; // 0 <= analogA <= 255 u8 analogB; // 0 <= analogB <= 255 + bool isConnected{true}; static const u8 MAIN_STICK_CENTER_X = 0x80; static const u8 MAIN_STICK_CENTER_Y = 0x80; From c62d83a34b34fe591dca1d3c03354ff915c589f4 Mon Sep 17 00:00:00 2001 From: Michael Maltese Date: Tue, 7 Feb 2017 16:25:27 -0800 Subject: [PATCH 3/3] GCPadEmu: only connected if default device connected This lets Dolphin know if a configured GameCube Controller should actually be treated as connected or not. Talked to @JMC47 a bit about this last night. My use-case is that all of my controllers are the same hardware (Xbox One controllers) so share the same configuration (modulo device number). Treating them all as always connected isn't a problem for most games, but in some (Smash Bros.) it forces me to go find a keyboard/mouse and unconfigure any controllers that I don't actually have connected. Hotplugging devices (works on macOS, at least) + this patch remove my need to ever touch the Controller Config dialog while in a game. This patch makes the following changes: - A new `BooleanSetting` in `GCPadEmu` called "Always Connected", which defaults to false. - `ControllerEmu` tracks whether the default device is connected on every call to `UpdateReferences()`. - `GCPadEmu.GetStatus()` now sets err bit to `PAD_ERR_NO_CONTROLLER` if the default device isn't connected. - `SIDevice_GCController` handles `PAD_ERR_NO_CONTROLLER` by imitating the behaviour of `SIDevice_Null` (as far as I can tell, this is the only use of the error bit from `GCPadStatus`). I wanted to add an OSD message akin to the ones when Wiimotes get connected/disconnected, but I haven't yet found where to put the logic. --- Source/Core/Core/HW/GCPadEmu.cpp | 10 ++++++++++ Source/Core/Core/HW/GCPadEmu.h | 3 ++- Source/Core/Core/HW/SI/SI_DeviceGCController.cpp | 15 +++++++++++++++ .../InputCommon/ControllerEmu/ControllerEmu.cpp | 7 +++++++ .../InputCommon/ControllerEmu/ControllerEmu.h | 2 ++ .../InputCommon/ControllerInterface/Device.cpp | 6 ++++++ .../Core/InputCommon/ControllerInterface/Device.h | 2 ++ 7 files changed, 44 insertions(+), 1 deletion(-) 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;