#include "InputDeviceTracker.h" #include "Framework/Application/SlateApplication.h" #include "GenericPlatform/GenericApplicationMessageHandler.h" #include "InputCoreTypes.h" // Last observed device classification. Read with no // synchronization; updates happen on the game thread // from Slate's input pipeline, and stale reads on // other threads are acceptable for this use case. // static ElxControllerType GLastControllerType = ElxControllerType::KeyboardMouse; // Keywords identifying a PlayStation-family gamepad. // Matched case-insensitively against the InputDeviceName // and HardwareDeviceIdentifier fields of the current // FInputDeviceScope. // static const TCHAR* const PlaystationKeywords[] = { TEXT("Playstation"), TEXT("PS3"), TEXT("PS4"), TEXT("PS5"), TEXT("PS6"), TEXT("PS7"), TEXT("Dualsense"), TEXT("Dualshock"), }; namespace { bool ContainsAnyPlaystationKeyword(const FString& Haystack) { for (const TCHAR* Keyword : PlaystationKeywords) { if (Haystack.Contains(Keyword, ESearchCase::IgnoreCase)) { return true; } } return false; } // Classifies the active gamepad by scanning the current // FInputDeviceScope. Defaults to Xbox; switches to // PlayStation only on a keyword match. // ElxControllerType ClassifyGamepadFromScope() { const FInputDeviceScope* Scope = FInputDeviceScope::GetCurrent(); if (Scope != nullptr) { if (ContainsAnyPlaystationKeyword(Scope->InputDeviceName.ToString()) || ContainsAnyPlaystationKeyword(Scope->HardwareDeviceIdentifier)) { return ElxControllerType::PlayStationGamepad; } } return ElxControllerType::XboxGamepad; } } bool FInputDeviceTrackerProcessor::HandleKeyDownEvent(FSlateApplication& SlateApp, const FKeyEvent& KeyEvent) { if (KeyEvent.GetKey().IsGamepadKey()) { GLastControllerType = ClassifyGamepadFromScope(); } else { GLastControllerType = ElxControllerType::KeyboardMouse; } return false; } bool FInputDeviceTrackerProcessor::HandleMouseButtonDownEvent(FSlateApplication& SlateApp, const FPointerEvent& MouseEvent) { GLastControllerType = ElxControllerType::KeyboardMouse; return false; } void UlxInputDeviceTracker::Initialize(FSubsystemCollectionBase& Collection) { Super::Initialize(Collection); if (FSlateApplication::IsInitialized()) { Processor = MakeShared(); FSlateApplication::Get().RegisterInputPreProcessor(Processor); } } void UlxInputDeviceTracker::Deinitialize() { if (Processor.IsValid() && FSlateApplication::IsInitialized()) { FSlateApplication::Get().UnregisterInputPreProcessor(Processor); } Processor.Reset(); Super::Deinitialize(); } ElxControllerType UlxInputDeviceTracker::GetLastControllerType() { return GLastControllerType; }