From 811c08b9f1a5fbd26867784f083cb7ee58a9633c Mon Sep 17 00:00:00 2001 From: Sixze <16257871+Sixze@users.noreply.github.com> Date: Sat, 27 May 2023 17:33:25 +0300 Subject: [PATCH] Rework device reconnection logic --- .../Private/DsInputDevice.cpp | 139 +++++++++++++----- .../FabulousDualSense/Private/DsInputDevice.h | 10 +- Source/FabulousDualSense/Public/DsConstants.h | 2 +- 3 files changed, 110 insertions(+), 41 deletions(-) diff --git a/Source/FabulousDualSense/Private/DsInputDevice.cpp b/Source/FabulousDualSense/Private/DsInputDevice.cpp index c64ae43..ea1b716 100644 --- a/Source/FabulousDualSense/Private/DsInputDevice.cpp +++ b/Source/FabulousDualSense/Private/DsInputDevice.cpp @@ -2,6 +2,7 @@ #include "DsSettings.h" #include "DsUtility.h" +#include "Containers/StaticBitArray.h" #include "Framework/Application/SlateApplication.h" #include "GenericPlatform/IInputInterface.h" #include "Misc/ConfigCacheIni.h" @@ -20,7 +21,7 @@ FDsInputDevice::~FDsInputDevice() { auto& InputDeviceMapper{IPlatformInputDeviceMapper::Get()}; - for (auto ControllerId{0}; ControllerId < DsConstants::MaxDevices; ControllerId++) + for (auto ControllerId{0}; ControllerId < DsConstants::MaxDevicesCount; ControllerId++) { if (DeviceContexts[ControllerId]._internal.connected) { @@ -44,7 +45,7 @@ void FDsInputDevice::SendControllerEvents() auto& InputDeviceMapper{IPlatformInputDeviceMapper::Get()}; - for (auto ControllerId{0}; ControllerId < DsConstants::MaxDevices; ControllerId++) + for (auto ControllerId{0}; ControllerId < DsConstants::MaxDevicesCount; ControllerId++) { if (!DeviceContexts[ControllerId]._internal.connected) { @@ -194,7 +195,7 @@ bool FDsInputDevice::Exec(UWorld* World, const TCHAR* Command, FOutputDevice& Ar void FDsInputDevice::SetChannelValue(const int32 ControllerId, const FForceFeedbackChannelType ChannelType, const float Value) { - if (ControllerId < 0 || ControllerId >= DsConstants::MaxDevices || !DeviceContexts[ControllerId]._internal.connected) + if (ControllerId < 0 || ControllerId >= DsConstants::MaxDevicesCount || !DeviceContexts[ControllerId]._internal.connected) { return; } @@ -233,7 +234,7 @@ void FDsInputDevice::SetChannelValue(const int32 ControllerId, const FForceFeedb void FDsInputDevice::SetChannelValues(const int32 ControllerId, const FForceFeedbackValues& Values) { - if (ControllerId < 0 || ControllerId >= DsConstants::MaxDevices || !DeviceContexts[ControllerId]._internal.connected) + if (ControllerId < 0 || ControllerId >= DsConstants::MaxDevicesCount || !DeviceContexts[ControllerId]._internal.connected) { return; } @@ -260,7 +261,7 @@ bool FDsInputDevice::IsGamepadAttached() const { auto bResult{false}; - for (auto i{0}; i < DsConstants::MaxDevices; i++) + for (auto i{0}; i < DsConstants::MaxDevicesCount; i++) { bResult |= DeviceContexts[i]._internal.connected; } @@ -270,13 +271,32 @@ bool FDsInputDevice::IsGamepadAttached() const void FDsInputDevice::RefreshDevices() { - static DS5W::DeviceEnumInfo DeviceInfos[DsConstants::MaxDevices]; - uint32 DevicesCount{0}; + static unsigned int KnownDeviceIds[DsConstants::MaxDevicesCount]; + unsigned int KnowDevicesCount{0}; - switch (const auto EnumDevicesResult{enumDevices(DeviceInfos, DsConstants::MaxDevices, &DevicesCount)}) + for (auto i{0}; i < DsConstants::MaxDevicesCount; i++) + { + if (DeviceContexts[i]._internal.connected) + { + KnownDeviceIds[i] = DeviceContexts[i]._internal.uniqueID; + KnowDevicesCount += 1; + } + } + + static DS5W::DeviceEnumInfo DeviceInfos[DsConstants::MaxDevicesCount]; + unsigned int DevicesCount{0}; + + const auto EnumDevicesResult{ + enumUnknownDevices(DeviceInfos, DsConstants::MaxDevicesCount, KnownDeviceIds, KnowDevicesCount, &DevicesCount) + }; + + switch (EnumDevicesResult) { case DS5W_OK: + break; + case DS5W_E_INSUFFICIENT_BUFFER: + DevicesCount = DsConstants::MaxDevicesCount; break; default: @@ -286,55 +306,103 @@ void FDsInputDevice::RefreshDevices() } auto& InputDeviceMapper{IPlatformInputDeviceMapper::Get()}; + TStaticBitArray ProcessedDeviceIndexes; - for (uint32 i{0}; i < DevicesCount; i++) - { - auto bAlreadyConnected{false}; - auto FreeIndex{-1}; + // First iteration: process devices reconnection and already connected devices. - for (auto j{0}; j < DsConstants::MaxDevices; j++) + for (unsigned int DeviceIndex{0}; DeviceIndex < DevicesCount; DeviceIndex++) + { + for (auto ControllerId{0}; ControllerId < DsConstants::MaxDevicesCount; ControllerId++) { - bAlreadyConnected |= DeviceInfos[i]._internal.uniqueID == DeviceContexts[j]._internal.uniqueID; - - if (FreeIndex < 0 && !DeviceContexts[j]._internal.connected) + if (DeviceContexts[ControllerId]._internal.uniqueID == DeviceInfos[DeviceIndex]._internal.uniqueID) { - FreeIndex = j; + ProcessedDeviceIndexes[DeviceIndex] = true; + + if (!DeviceContexts[ControllerId]._internal.connected) + { + ConnectDevice(InputDeviceMapper, DeviceInfos[DeviceIndex], ControllerId); + } + + break; } } + } - if (bAlreadyConnected || FreeIndex < 0) + // Second iteration: process the connection of new devices (without reusing the + // IDs of disconnected devices to give them the opportunity to reconnect later). + + for (unsigned int DeviceIndex{0}; DeviceIndex < DevicesCount; DeviceIndex++) + { + if (ProcessedDeviceIndexes[DeviceIndex]) { continue; } - UE_LOG(LogFabulousDualSense, Log, TEXT("New device found: %s, Connection: %s."), - DeviceInfos[i]._internal.path, DsUtility::DeviceConnectionToString(DeviceInfos[i]._internal.connection).GetData()); - - const auto InitializeDeviceContextResult{initDeviceContext(&DeviceInfos[i], &DeviceContexts[FreeIndex])}; - if (DS5W_SUCCESS(InitializeDeviceContextResult)) + for (auto ControllerId{0}; ControllerId < DsConstants::MaxDevicesCount; ControllerId++) { - UE_LOG(LogFabulousDualSense, Log, TEXT("Device connected: %s."), DeviceInfos[i]._internal.path); + if (DeviceContexts[ControllerId]._internal.uniqueID == 0) + { + ProcessedDeviceIndexes[DeviceIndex] = true; - FMemory::Memzero(InputStates[FreeIndex]); - FMemory::Memzero(OutputStates[FreeIndex]); - FMemory::Memzero(ExtraStates[FreeIndex]); + ConnectDevice(InputDeviceMapper, DeviceInfos[DeviceIndex], ControllerId); + break; + } + } + } - auto PlatformUserId{PLATFORMUSERID_NONE}; - auto InputDeviceId{INPUTDEVICEID_NONE}; - InputDeviceMapper.RemapControllerIdToPlatformUserAndDevice(i, PlatformUserId, InputDeviceId); + // Third iteration: process the connection of new devices (reusing the IDs of + // disconnected devices, because there are not enough unused IDs for new devices). - InputDeviceMapper.Internal_MapInputDeviceToUser(InputDeviceId, PlatformUserId, EInputDeviceConnectionState::Connected); + for (unsigned int DeviceIndex{0}; DeviceIndex < DevicesCount; DeviceIndex++) + { + if (ProcessedDeviceIndexes[DeviceIndex]) + { + continue; } - else + + for (auto ControllerId{0}; ControllerId < DsConstants::MaxDevicesCount; ControllerId++) { - UE_LOG(LogFabulousDualSense, Warning, TEXT("Failed to initialize device context: %s, Device: %s."), - DsUtility::ReturnValueToString(InitializeDeviceContextResult).GetData(), DeviceInfos[i]._internal.path); + if (!DeviceContexts[ControllerId]._internal.connected) + { + ProcessedDeviceIndexes[DeviceIndex] = true; - FMemory::Memzero(DeviceContexts[FreeIndex]); + ConnectDevice(InputDeviceMapper, DeviceInfos[DeviceIndex], ControllerId); + break; + } } } } +void FDsInputDevice::ConnectDevice(IPlatformInputDeviceMapper& InputDeviceMapper, + DS5W::DeviceEnumInfo& DeviceInfo, const int32 ControllerId) +{ + UE_LOG(LogFabulousDualSense, Log, TEXT("New device found: %s, Connection: %s."), + DeviceInfo._internal.path, DsUtility::DeviceConnectionToString(DeviceInfo._internal.connection).GetData()); + + const auto InitializeDeviceContextResult{initDeviceContext(&DeviceInfo, &DeviceContexts[ControllerId])}; + if (DS5W_SUCCESS(InitializeDeviceContextResult)) + { + UE_LOG(LogFabulousDualSense, Log, TEXT("Device connected: %s."), DeviceInfo._internal.path); + + FMemory::Memzero(InputStates[ControllerId]); + FMemory::Memzero(OutputStates[ControllerId]); + FMemory::Memzero(ExtraStates[ControllerId]); + + auto PlatformUserId{PLATFORMUSERID_NONE}; + auto InputDeviceId{INPUTDEVICEID_NONE}; + InputDeviceMapper.RemapControllerIdToPlatformUserAndDevice(ControllerId, PlatformUserId, InputDeviceId); + + InputDeviceMapper.Internal_MapInputDeviceToUser(InputDeviceId, PlatformUserId, EInputDeviceConnectionState::Connected); + } + else + { + UE_LOG(LogFabulousDualSense, Warning, TEXT("Failed to initialize device context: %s, Device: %s."), + DsUtility::ReturnValueToString(InitializeDeviceContextResult).GetData(), DeviceInfo._internal.path); + + FMemory::Memzero(DeviceContexts[ControllerId]); + } +} + void FDsInputDevice::DisconnectDevice(IPlatformInputDeviceMapper& InputDeviceMapper, const int32 ControllerId, const FPlatformUserId PlatformUserId, const FInputDeviceId InputDeviceId) { @@ -343,7 +411,6 @@ void FDsInputDevice::DisconnectDevice(IPlatformInputDeviceMapper& InputDeviceMap UE_LOG(LogFabulousDualSense, Log, TEXT("Device disconnected: %s."), Context._internal.devicePath); freeDeviceContext(&Context); - Context._internal.uniqueID = 0; if (FSlateApplication::Get().GetPlatformApplication().IsValid()) { diff --git a/Source/FabulousDualSense/Private/DsInputDevice.h b/Source/FabulousDualSense/Private/DsInputDevice.h index 5d99b47..36a88b1 100644 --- a/Source/FabulousDualSense/Private/DsInputDevice.h +++ b/Source/FabulousDualSense/Private/DsInputDevice.h @@ -31,13 +31,13 @@ class FABULOUSDUALSENSE_API FDsInputDevice : public IInputDevice float ButtonRepeatDelay{0.1f}; - DS5W::DeviceContext DeviceContexts[DsConstants::MaxDevices]{}; + DS5W::DeviceContext DeviceContexts[DsConstants::MaxDevicesCount]{}; - DS5W::DS5InputState InputStates[DsConstants::MaxDevices]{}; + DS5W::DS5InputState InputStates[DsConstants::MaxDevicesCount]{}; - DS5W::DS5OutputState OutputStates[DsConstants::MaxDevices]{}; + DS5W::DS5OutputState OutputStates[DsConstants::MaxDevicesCount]{}; - FDsExtraState ExtraStates[DsConstants::MaxDevices]{}; + FDsExtraState ExtraStates[DsConstants::MaxDevicesCount]{}; public: explicit FDsInputDevice(const TSharedRef& MessageHandler); @@ -61,6 +61,8 @@ class FABULOUSDUALSENSE_API FDsInputDevice : public IInputDevice private: void RefreshDevices(); + void ConnectDevice(IPlatformInputDeviceMapper& InputDeviceMapper, DS5W::DeviceEnumInfo& DeviceInfo, int32 ControllerId); + void DisconnectDevice(IPlatformInputDeviceMapper& InputDeviceMapper, int32 ControllerId, FPlatformUserId PlatformUserId, FInputDeviceId InputDeviceId); diff --git a/Source/FabulousDualSense/Public/DsConstants.h b/Source/FabulousDualSense/Public/DsConstants.h index 020d862..6ef1e23 100644 --- a/Source/FabulousDualSense/Public/DsConstants.h +++ b/Source/FabulousDualSense/Public/DsConstants.h @@ -8,7 +8,7 @@ namespace DsConstants inline static const FName InputDeviceName{TEXTVIEW("DsInputDevice")}; inline static const FString HardwareDeviceIdentifier{TEXTVIEW("DualSense")}; - inline static constexpr auto MaxDevices{4}; + inline static constexpr auto MaxDevicesCount{4}; inline static constexpr auto ButtonsCount{29}; inline static constexpr auto StickDeadZone{30}; inline static constexpr auto TriggerDeadZone{30};