// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "IInputDevice.h" #include "Misc/CoreMiscDefines.h" // For FInputDeviceId/FPlatformUserId #if GAME_INPUT_SUPPORT THIRD_PARTY_INCLUDES_START #include "Microsoft/AllowMicrosoftPlatformTypes.h" #include #include "Microsoft/HideMicrosoftPlatformTypes.h" THIRD_PARTY_INCLUDES_END #include "Microsoft/COMPointer.h" #endif // GAME_INPUT_SUPPORT #include "GameInputDeviceContainer.h" /** * IInputDevice interface for the Game Input library. This is a base class * that is intended to be implemented on each platform that supports it (Xbox and PC). * * This stores all state about every unique Human Interface Device that the GameInput library * detects. * * Any implementors of this interface should be Created in an IInputDevice module's CreateInputDevice function * (IInputDeviceModule::CreateInputDevice), and have it's Initialize function called */ class IGameInputDeviceInterface : public IInputDevice { public: GAMEINPUTBASE_API explicit IGameInputDeviceInterface(const TSharedRef& InMessageHandler, struct IGameInput* InGameInput); GAMEINPUTBASE_API virtual ~IGameInputDeviceInterface() override; /** * Init function that should be called post-construction of this object. * This is required for sending controller events and will ensure if not called. */ GAMEINPUTBASE_API void Initialize(); protected: //~ Begin IInputDevice interface GAMEINPUTBASE_API virtual void Tick(float DeltaTime) override; GAMEINPUTBASE_API virtual void SendControllerEvents() override; GAMEINPUTBASE_API virtual void SetMessageHandler(const TSharedRef& InMessageHandler) override; GAMEINPUTBASE_API virtual bool Exec(UWorld* InWorld, const TCHAR* Cmd, FOutputDevice& Ar) override; GAMEINPUTBASE_API virtual void SetChannelValue(int32 ControllerId, FForceFeedbackChannelType ChannelType, float Value) override; GAMEINPUTBASE_API virtual void SetChannelValues(int32 ControllerId, const FForceFeedbackValues& values) override; GAMEINPUTBASE_API virtual bool IsGamepadAttached() const override; //~End IInputDevice interface #if GAME_INPUT_SUPPORT /** Returns a mask of the currently supported Game Input Kind that we want to get the reading of. */ GAMEINPUTBASE_API virtual GameInputKind GetCurrentGameInputKindSupport() const; /** Binds a listener for device status changes from game input to this class */ GAMEINPUTBASE_API virtual bool BindDeviceStatusCallbacks(); /** * A callback for when an input device connection change has been detected. */ GAMEINPUTBASE_API virtual void OnDeviceConnectionChanged(GameInputCallbackToken CallbackToken, IGameInputDevice* Device, uint64 Timestamp, GameInputDeviceStatus CurrentStatus, GameInputDeviceStatus PreviousStatus); /** * Mark this device as disconnected and invalidate the tracked game input device. A disconnected device will stay in the * GameInputSourceDevices with a null Device pointer. */ virtual void HandleDeviceDisconnected(IGameInputDevice* Device, uint64 Timestamp) = 0; /** * Map this new input device to a platform user and initialize the known FGameInputDeviceInfo. * If this is a new connection, this will request a new FInputDeviceId from the platform input device mapper * and add it to the GameInputSourceDevices map. */ virtual void HandleDeviceConnected(IGameInputDevice* Device, uint64 Timestamp) = 0; /** Process any deferred device connection changes that may have occurred. This should only be called on the game thread. */ GAMEINPUTBASE_API void ProcessDeferredDeviceConnectionChanges(); /** Callbacks for when the app is constrained/unconstrained (i.e. you Alt + Tab out of the window, or open the home menu on a console platform) */ GAMEINPUTBASE_API void OnAppConstrained(); GAMEINPUTBASE_API void OnAppUnconstrained(); /** Called on the first update after the was un-constrained. */ GAMEINPUTBASE_API void DetermineStateAfterFirstUnconstrainedUpdate(); /** Returns a matching FGameInputDeviceContainer if one exists for the given GameInput device. Nullptr if none exist. */ GAMEINPUTBASE_API FGameInputDeviceContainer* GetDeviceData(IGameInputDevice* InDevice); /** * Returns a pointer to the Device info associated with the given IGameInputDevice. * * If one doesn't exist, then create a new one and return that. */ GAMEINPUTBASE_API FGameInputDeviceContainer* GetOrCreateDeviceData(IGameInputDevice* InDevice); /** * Creates a new FGameInputDeviceContainer* and stores it in DeviceData. It is up to each implementing * device interface to how that device is mapped to platform users and initialized. */ virtual FGameInputDeviceContainer* CreateDeviceData(IGameInputDevice* InDevice) = 0; /** * This will update the CurrentlyConnectedDeviceTypes bitmask based on the current set of DeviceData */ GAMEINPUTBASE_API virtual void EnumerateCurrentlyConnectedDeviceTypes(); /** Message handler that we can use to tell the engine about input events */ TSharedRef MessageHandler; /** Pointer to the Game Input interface object */ TComPtr GameInput; // CS for OnDeviceConnectionChanged called from background system thread and PollGameDeviceState called from Main thread FCriticalSection DeviceInfoCS; /** Token for when a device connection change happens */ GameInputCallbackToken ConnectionChangeCallbackToken; /** An enumeration of all the currently registered Game input Devices. */ GameInputKind CurrentlyConnectedDeviceTypes; /** Set to true if the IGameInputDeviceInterface::Initialize function was called. This is required for sending controller events. */ bool bWasinitialized; /** True if the app is currently constrained this tick */ bool bIsAppCurrentlyConstrained; /** True if the app was constrained last tick */ bool bWasAppConstrainedLastTick; // Array of Input Device data for every connected Game Input Device. TArray> DeviceData; // A mapping of a platform user to the most recently used Input Device for that user TMap> PlatformUserIdToMostRecentDeviceContainer; /** Stores some data about when device connection changes happen to be processed later */ struct FDeferredDeviceConnectionChanges { FDeferredDeviceConnectionChanges() = default; /** The GameInput device that has changed */ IGameInputDevice* Device = nullptr; /** Timestamp of when the connection state change happened */ uint64 Timestamp = 0; /** The evaluated status of the game input device */ EInputDeviceConnectionState Status = EInputDeviceConnectionState::Invalid; /** The current GameInput status of the device */ GameInputDeviceStatus CurrentStatus = GameInputDeviceStatus::GameInputDeviceNoStatus; /** The previous GameInput status of the device */ GameInputDeviceStatus PreviousStatus = GameInputDeviceStatus::GameInputDeviceNoStatus; }; /** Array of device connection changed events that will be processed in ProcessDeferredDeviceConnectionChanges. */ TArray DeferredDeviceConnectionChanges; #endif // #if GAME_INPUT_SUPPORT };