diff --git a/Common/System/System.h b/Common/System/System.h index e7135a2175..b08ad08ce1 100644 --- a/Common/System/System.h +++ b/Common/System/System.h @@ -260,6 +260,7 @@ enum class SystemNotification { UI_STATE_CHANGED, AUDIO_MODE_CHANGED, APP_SWITCH_MODE_CHANGED, + PAD_STATE_CHANGED, }; // I guess it's not super great architecturally to centralize this, since it's not general - but same with a lot of diff --git a/Core/KeyMap.cpp b/Core/KeyMap.cpp index e3f0de9dc7..d0fb5cb27e 100644 --- a/Core/KeyMap.cpp +++ b/Core/KeyMap.cpp @@ -839,25 +839,64 @@ bool HasBuiltinController(std::string_view name) { } void NotifyPadConnected(InputDeviceID deviceId, std::string_view name) { - std::lock_guard guard(g_controllerMapLock); - g_seenPads.insert(std::string(name)); - g_padNames[deviceId] = name; + { + std::lock_guard guard(g_controllerMapLock); + g_seenPads.insert(std::string(name)); + g_padNames[deviceId] = name; + } + System_Notify(SystemNotification::PAD_STATE_CHANGED); } void NotifyPadDisconnected(InputDeviceID deviceId) { - std::lock_guard guard(g_controllerMapLock); - auto iter = g_padNames.find(deviceId); - if (iter != g_padNames.end()) { - g_seenPads.erase(iter->second); + { + std::lock_guard guard(g_controllerMapLock); + auto iter = g_padNames.find(deviceId); + if (iter != g_padNames.end()) { + g_seenPads.erase(iter->second); + } + g_padNames.erase(deviceId); + } + System_Notify(SystemNotification::PAD_STATE_CHANGED); +} + +void ClearControlsWithDeviceId(InputDeviceID deviceId) { + bool modified = false; + std::lock_guard guard(g_controllerMapLock); + for (auto iter = g_controllerMap.begin(); iter != g_controllerMap.end(); ++iter) { + auto &mappings = iter->second; + for (auto mapIter = mappings.begin(); mapIter != mappings.end(); ) { + bool found = false; + for (auto &mapping : mapIter->mappings) { + if (mapping.deviceId == deviceId) { + found = true; + break; + } + } + if (found) { + mapIter = mappings.erase(mapIter); + modified = true; + } else { + ++mapIter; + } + } + } + + if (modified) { + g_controllerMapGeneration++; } - g_padNames.erase(deviceId); } void AutoConfForPad(std::string_view name) { std::lock_guard guard(g_controllerMapLock); - g_controllerMap.clear(); - INFO_LOG(Log::System, "Autoconfiguring pad for '%.*s'", STR_VIEW(name)); + InputDeviceID deviceId = DEVICE_ID_PAD_0; + for (auto [padDeviceId, padName] : g_padNames) { + if (padName == name) { + // Already configured. + deviceId = padDeviceId; + } + } + ClearControlsWithDeviceId(deviceId); #if PPSSPP_PLATFORM(ANDROID) if (name.find("Xbox") != std::string::npos) { @@ -881,8 +920,10 @@ void AutoConfForPad(std::string_view name) { #endif // Add a couple of convenient keyboard mappings by default, too. +#if !defined(MOBILE_DEVICE) g_controllerMap[VIRTKEY_PAUSE].push_back(MultiInputMapping(InputMapping(DEVICE_ID_KEYBOARD, NKCODE_ESCAPE))); g_controllerMap[VIRTKEY_FASTFORWARD].push_back(MultiInputMapping(InputMapping(DEVICE_ID_KEYBOARD, NKCODE_TAB))); +#endif g_controllerMapGeneration++; } diff --git a/Windows/HidInputDevice.cpp b/Windows/HidInputDevice.cpp index 09665bf1c2..8e97bb8951 100644 --- a/Windows/HidInputDevice.cpp +++ b/Windows/HidInputDevice.cpp @@ -15,6 +15,7 @@ #include "Common/Common.h" #include "Common/System/NativeApp.h" #include "Common/System/OSD.h" +#include "Core/KeyMap.h" constexpr u8 LED_R = 0x05; constexpr u8 LED_G = 0x10; @@ -184,16 +185,14 @@ static const HIDControllerInfo g_psInfos[] = { // {PSSubType::DS5, DUALSENSE_EDGE_WIRELESS}, }; -static bool IsSupportedGamepad(HANDLE handle, USHORT *pidOut, HIDControllerType *subType) { +static const HIDControllerInfo *GetGamepadInfo(HANDLE handle) { HIDD_ATTRIBUTES attr{sizeof(HIDD_ATTRIBUTES)}; if (!HidD_GetAttributes(handle, &attr)) { return false; } for (const auto &info : g_psInfos) { if (attr.VendorID == info.vendorId && attr.ProductID == info.productId) { - *pidOut = attr.ProductID; - *subType = info.type; - return true; + return &info; } } return false; @@ -279,6 +278,10 @@ static bool ShutdownDualsense(HANDLE handle, int outReportSize) { return WriteReport(handle, report); } +static bool InitializeSwitchPro(HANDLE handle) { + return true; +} + enum class DS4FeatureBits : u8 { VOL_L = 0x10, VOL_R = 0x20, @@ -350,7 +353,7 @@ static bool ShutdownDualShock(HANDLE handle, int outReportSize) { return WriteReport(handle, report); } -HANDLE OpenFirstHIDController(HIDControllerType *subType, int *reportSize, int *outReportSize) { +static HANDLE OpenFirstHIDController(HIDControllerType *subType, int *reportSize, int *outReportSize, const HIDControllerInfo **outInfo) { GUID hidGuid; HidD_GetHidGuid(&hidGuid); @@ -373,9 +376,11 @@ HANDLE OpenFirstHIDController(HIDControllerType *subType, int *reportSize, int * HANDLE handle = CreateFile(detailData->DevicePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); if (handle != INVALID_HANDLE_VALUE) { - USHORT pid; - if (IsSupportedGamepad(handle, &pid, subType)) { - INFO_LOG(Log::UI, "Found supported gamepad. PID: %04x", pid); + const HIDControllerInfo *info = GetGamepadInfo(handle); + *outInfo = info; + if (info) { + *subType = info->type; + INFO_LOG(Log::UI, "Found supported gamepad. PID: %04x", info->productId); HIDP_CAPS caps; PHIDP_PREPARSED_DATA preparsedData; @@ -396,7 +401,7 @@ HANDLE OpenFirstHIDController(HIDControllerType *subType, int *reportSize, int * result = InitializeDualShock(handle, *outReportSize); break; case HIDControllerType::SwitchPro: - result = true; // InitializeSwitchPro(handle, *outReportSize); + result = InitializeSwitchPro(handle); break; } @@ -677,13 +682,20 @@ InputDeviceID HidInputDevice::DeviceID(int pad) { } int HidInputDevice::UpdateState() { + const InputDeviceID deviceID = DeviceID(pad_); + if (!controller_) { // Poll for controllers from time to time. if (pollCount_ == 0) { pollCount_ = POLL_FREQ; - HANDLE newController = OpenFirstHIDController(&subType_, &reportSize_, &outReportSize_); + const HIDControllerInfo *info{}; + HANDLE newController = OpenFirstHIDController(&subType_, &reportSize_, &outReportSize_, &info); if (newController) { controller_ = newController; + if (info) { + name_ = info->name; + } + KeyMap::NotifyPadConnected(deviceID, name_); } } else { pollCount_--; @@ -706,7 +718,6 @@ int HidInputDevice::UpdateState() { } if (result) { - const InputDeviceID deviceID = DeviceID(pad_); // Process the input and generate input events. const u32 downMask = state.buttons & (~prevState_.buttons); const u32 upMask = (~state.buttons) & prevState_.buttons; @@ -757,6 +768,7 @@ int HidInputDevice::UpdateState() { return UPDATESTATE_NO_SLEEP; // The ReadFile sleeps for us, effectively. } else { // might have been disconnected. retry later. + KeyMap::NotifyPadDisconnected(deviceID); ReleaseAllKeys(buttonMappings, buttonMappingsSize); CloseHandle(controller_); controller_ = NULL; diff --git a/Windows/HidInputDevice.h b/Windows/HidInputDevice.h index 7cf44261cb..8772e7d98c 100644 --- a/Windows/HidInputDevice.h +++ b/Windows/HidInputDevice.h @@ -47,6 +47,7 @@ private: HIDControllerType subType_{}; HANDLE controller_; + std::string name_; int pad_ = 0; int pollCount_ = 0; int reportSize_ = 0;