//=========== Copyright Valve Corporation, All rights reserved. ===============// // // Purpose: //=============================================================================// #ifndef IUIINPUT_H #define IUIINPUT_H #ifdef _WIN32 #pragma once #endif #include "keycodes.h" #include "mousecodes.h" #include "gamepadcodes.h" #include "tier0/platform.h" #include "tier1/utldelegate.h" #include "../controls/panelhandle.h" #include "../uieventcodes.h" #include "../iuiengine.h" #ifdef SOURCE2_PANORAMA #include "inputsystem/buttoncode.h" #endif namespace panorama { class CPanel2D; class IImageSource; class IUISettings; // the classes of input we understand enum EInputType { k_eInputNone = 0, k_eKeyDown = 1, // raw down press k_eKeyUp = 2, // raw release k_eKeyChar = 3, // composited text entry from the OS k_eMouseDown = 4, k_eMouseUp = 5, k_eMouseMove = 6, k_eMouseDoubleClick = 7, k_eMouseTripleClick = 8, k_eMouseWheel = 9, k_eMouseEnter = 10, k_eMouseLeave = 11, k_eGamePadDown = 12, k_eGamePadUp = 13, k_eGamePadAnalog = 14, k_eOverlayCommand = 5000, k_eInputTypeMaxRange = 0xFFFFFFFF // force size to 32 bits }; enum EActiveControllerType { k_EActiveControllerType_None, // we aren't using a controller or we don't know to do k_EActiveControllerType_XInput, k_EActiveControllerType_Steam, }; // // structs container input type specific data // struct KeyData_t { EPanelEventSource_t m_eSource; // this needs to be the first field of the struct, since it's unioned in InputMessage_t KeyCode m_KeyCode; uint8 m_RepeatCount; bool m_bFirstDown; // is this the first time this key was pressed wchar_t m_UniChar; // unicode equivalent of this key uint32 m_Modifiers; // alt, ctrl, etc held down? }; struct MouseData_t { EPanelEventSource_t m_eSource; // this needs to be the first field of the struct, since it's unioned in InputMessage_t MouseCode m_MouseCode; uint32 m_Modifiers; uint8 m_RepeatCount; int m_Delta; }; struct GamePadData_t { EPanelEventSource_t m_eSource; // this needs to be the first field of the struct, since it's unioned in InputMessage_t GamePadCode m_GamePadCode; uint8 m_RepeatCount; // home many times in a row we have had this button down float m_fValue; // the analog value of the deflection if an axis // if an analog event then these two are set for each axis value float m_fValueX; // the analog value of the deflection along horizontal float m_fValueY; // the analog value of the deflection along vertical // For Steam controller analog events this value will indicate the time the users finger went down float m_flFingerDown; // For Steam controller analog events these values indicate the starting finger position (so you can do some basic swipe stuff) float m_fValueXFirst; float m_fValueYFirst; // For Steam controller analog events this is the raw sampled coordinate without deadzoning float m_fValueXRaw; float m_fValueYRaw; }; struct InputMessage_t { EInputType m_eInputType; float m_flInputTime; union { EPanelEventSource_t m_eSource; // where did this event originate? this is the first field of the other *Data_t structs below. KeyData_t m_KeyData; MouseData_t m_MouseData; GamePadData_t m_GamePadData; }; }; // // A combination of event type and specific code data to mean an input event, like on key down of the A key // struct ActionInput_t { ActionInput_t() { m_InputType = k_eInputNone; m_Data.m_KeyCode = KEY_NONE; m_unModifiers = MODIFIER_NONE; } explicit ActionInput_t( EInputType type, KeyCode code, uint32 unModifiers, const char *pchNamespace ) { m_InputType = type; m_Data.m_KeyCode = code; m_unModifiers = unModifiers; if ( pchNamespace && pchNamespace[0] ) m_symNameSpace = pchNamespace; } explicit ActionInput_t( EInputType type, GamePadCode code, const char *pchNamespace ) { m_InputType = type; m_Data.m_GamePadCode = code; m_unModifiers = MODIFIER_NONE; if ( pchNamespace && pchNamespace[0] ) m_symNameSpace = pchNamespace; } explicit ActionInput_t( EInputType type, MouseCode code, const char *pchNamespace ) { m_InputType = type; m_Data.m_MouseCode = code; m_unModifiers = MODIFIER_NONE; if ( pchNamespace && pchNamespace[0] ) m_symNameSpace = pchNamespace; } ActionInput_t( InputMessage_t &msg, const char *pchNamespace ) { m_InputType = msg.m_eInputType; if ( pchNamespace && pchNamespace[0] ) m_symNameSpace = pchNamespace; m_unModifiers = MODIFIER_NONE; switch ( msg.m_eInputType ) { default: AssertMsg( false, "Unknown input type to ActionInput_t( InputMessage_t )" ); break; case k_eKeyDown: case k_eKeyUp: case k_eKeyChar: m_Data.m_KeyCode = msg.m_KeyData.m_KeyCode; m_unModifiers = msg.m_KeyData.m_Modifiers; break; case k_eMouseDown: case k_eMouseDoubleClick: case k_eMouseTripleClick: case k_eMouseUp: case k_eMouseMove: case k_eMouseWheel: m_Data.m_MouseCode = msg.m_MouseData.m_MouseCode; m_unModifiers = msg.m_MouseData.m_Modifiers; break; case k_eMouseEnter: case k_eMouseLeave: break; case k_eGamePadDown: case k_eGamePadUp: case k_eGamePadAnalog: m_Data.m_GamePadCode = msg.m_GamePadData.m_GamePadCode; break; } } // Can't ever make this not 32bits in size, see crazy comparison operators below. Also, each // member must be exactly 32bits, not less with uninitialized data. EInputType m_InputType; union { KeyCode m_KeyCode; GamePadCode m_GamePadCode; MouseCode m_MouseCode; } m_Data; uint32 m_unModifiers; CPanoramaSymbol m_symNameSpace; bool operator<( const ActionInput_t &that ) const { if ( m_InputType != that.m_InputType ) return m_InputType < that.m_InputType; if ( m_unModifiers != that.m_unModifiers ) return m_unModifiers < that.m_unModifiers; // I have a namespace and you don't if ( m_symNameSpace.IsValid() && !that.m_symNameSpace.IsValid() ) return true; // You have a namespace and I don't if ( that.m_symNameSpace.IsValid() && !m_symNameSpace.IsValid() ) return false; // compare namespace if both are valid but not equal if ( m_symNameSpace.IsValid() && that.m_symNameSpace.IsValid() && m_symNameSpace != that.m_symNameSpace ) return m_symNameSpace < that.m_symNameSpace; // lets compare the raw code now switch( m_InputType ) { default: case k_eKeyDown: case k_eKeyUp: case k_eKeyChar: return m_Data.m_KeyCode < that.m_Data.m_KeyCode; case k_eMouseDown: case k_eMouseUp: case k_eMouseMove: case k_eMouseWheel: case k_eMouseDoubleClick: case k_eMouseTripleClick: return m_Data.m_MouseCode < that.m_Data.m_MouseCode; case k_eGamePadDown: case k_eGamePadUp: case k_eGamePadAnalog: return m_Data.m_GamePadCode < that.m_Data.m_GamePadCode; } } bool operator==( const ActionInput_t &that ) const { if ( m_InputType == that.m_InputType && m_unModifiers == that.m_unModifiers && // also if both namespace are valid and equal OR either namespace is unset (i.e "global") ( ( m_symNameSpace.IsValid() && that.m_symNameSpace.IsValid() && m_symNameSpace == that.m_symNameSpace ) || ( !m_symNameSpace.IsValid() && !that.m_symNameSpace.IsValid() ) ) ) { switch( m_InputType ) { default: case k_eKeyDown: case k_eKeyUp: case k_eKeyChar: return m_Data.m_KeyCode == that.m_Data.m_KeyCode; case k_eMouseDoubleClick: case k_eMouseTripleClick: case k_eMouseDown: case k_eMouseUp: case k_eMouseMove: case k_eMouseWheel: return m_Data.m_MouseCode == that.m_Data.m_MouseCode; case k_eGamePadDown: case k_eGamePadUp: case k_eGamePadAnalog: return m_Data.m_GamePadCode == that.m_Data.m_GamePadCode; } } return false; } }; // Helpers for checking modifier state inline bool IsControlPressed( uint32 unModifiers ) { return unModifiers & MODIFIER_LCONTROL || unModifiers & MODIFIER_RCONTROL; } inline bool IsAltPressed( uint32 unModifiers ) { return unModifiers & MODIFIER_LALT || unModifiers & MODIFIER_RALT; } inline bool IsShiftPressed( uint32 unModifiers ) { return unModifiers & MODIFIER_LSHIFT || unModifiers & MODIFIER_RSHIFT; } inline bool IsWinPressed( uint32 unModifiers ) { return unModifiers & MODIFIER_LWIN || unModifiers & MODIFIER_RWIN; } // // struct to wrap mouse move events for mouse tracked panels // struct MouseTrackingResults_t { MouseTrackingResults_t() { m_hPanel = k_ulInvalidPanelHandle64; m_flX = 0.0f; m_flY = 0.0f; } MouseTrackingResults_t( uint64 handle, float x, float y ) { m_hPanel = handle; m_flX = x; m_flY = y; } uint64 m_hPanel; float m_flX; float m_flY; }; // // An interface to receive captured input // class IInputCapture { public: // keyboard virtual bool OnCapturedKeyDown( IUIPanel *pPanel, const KeyData_t &code ) = 0; virtual bool OnCapturedKeyUp( IUIPanel *pPanel, const KeyData_t &code ) = 0; virtual bool OnCapturedKeyTyped( IUIPanel *pPanel, const KeyData_t &unichar ) = 0; // mouse virtual bool OnCapturedMouseMove( IUIPanel *pPanel ) = 0; virtual bool OnCapturedMouseButtonDown( IUIPanel *pPanel, const MouseData_t &code ) = 0; virtual bool OnCapturedMouseButtonUp( IUIPanel *pPanel, const MouseData_t &code ) = 0; virtual bool OnCapturedMouseButtonDoubleClick( IUIPanel *pPanel, const MouseData_t &code ) = 0; virtual bool OnCapturedMouseButtonTripleClick( IUIPanel *pPanel, const MouseData_t &code ) = 0; virtual bool OnCapturedMouseWheel( IUIPanel *pPanel, const MouseData_t &code ) = 0; // gamepad virtual bool OnCapturedGamePadDown( IUIPanel *pPanel, const GamePadData_t &code ) = 0; virtual bool OnCapturedGamePadUp( IUIPanel *pPanel, const GamePadData_t &code ) = 0; virtual bool OnCapturedGamePadAnalog( IUIPanel *pPanel, const GamePadData_t &code ) = 0; }; class CDefaultInputCapture : public IInputCapture { public: // keyboard virtual bool OnCapturedKeyDown( panorama::IUIPanel *pPanel, const panorama::KeyData_t &code ) OVERRIDE { return false; } virtual bool OnCapturedKeyUp( panorama::IUIPanel *pPanel, const panorama::KeyData_t &code ) OVERRIDE { return false; } virtual bool OnCapturedKeyTyped( panorama::IUIPanel *pPanel, const panorama::KeyData_t &unichar ) OVERRIDE { return false; } // mouse virtual bool OnCapturedMouseMove( panorama::IUIPanel *pPanel ) OVERRIDE { return false; } virtual bool OnCapturedMouseButtonDown( panorama::IUIPanel *pPanel, const panorama::MouseData_t &code ) OVERRIDE { return false; } virtual bool OnCapturedMouseButtonUp( panorama::IUIPanel *pPanel, const panorama::MouseData_t &code ) OVERRIDE { return false; } virtual bool OnCapturedMouseButtonDoubleClick( panorama::IUIPanel *pPanel, const panorama::MouseData_t &code ) OVERRIDE { return false; } virtual bool OnCapturedMouseButtonTripleClick( panorama::IUIPanel *pPanel, const panorama::MouseData_t &code ) OVERRIDE { return false; } virtual bool OnCapturedMouseWheel( panorama::IUIPanel *pPanel, const panorama::MouseData_t &code ) OVERRIDE { return false; } // gamepad virtual bool OnCapturedGamePadDown( panorama::IUIPanel *pPanel, const panorama::GamePadData_t &code ) OVERRIDE { return false; } virtual bool OnCapturedGamePadUp( panorama::IUIPanel *pPanel, const panorama::GamePadData_t &code ) OVERRIDE { return false; } virtual bool OnCapturedGamePadAnalog( panorama::IUIPanel *pPanel, const panorama::GamePadData_t &code ) OVERRIDE { return false; } }; // // Handles per top level window focus // class IUIWindowInput { public: virtual bool InputEvent( InputMessage_t &msg, bool bNewEvent = true ) = 0; // Receive mouse move events, in window coordinate space virtual void OnMouseMove( float flMouseX, float flMouseY, bool bSynthesized = false ) = 0; // current mouse coordinates and visibility virtual void GetSurfaceMousePosition( float &x, float &y ) = 0; virtual bool BCursorVisible() = 0; virtual void WakeupMouseCursor() = 0; virtual void FadeOutCursorNow() = 0; // gamepad state virtual int GetNumGamepadsConnected() = 0; virtual bool BWasGamepadConnectedThisSession() = 0; virtual bool BWasGamepadUsedThisSession() = 0; virtual bool BWasSteamControllerConnectedThisSession() = 0; virtual bool BWasSteamControllerUsedThisSession() = 0; // tracking of last input type virtual bool BWasGamepadLastInputSource() = 0; virtual bool BWasMouseLastInputSource() = 0; virtual bool BWasKeyboardOrMouseLastInputSource() = 0; // Get the last input source virtual EPanelEventSource_t GetLastPanelEventSource() = 0; // Keyboard / mouse info virtual bool BWasKeyboardOrMouseUsedThisSession() = 0; virtual bool BWasMouseMovedThisSession() = 0; // top level OS window support virtual void GotWindowFocus() = 0; virtual void LostWindowFocus() = 0; virtual bool BHasWindowFocus() = 0; // Window can temporarily disable all input, used for overlay when the game is focused, but overlay inactive virtual bool BAllowInput( InputMessage_t &msg ) = 0; // panel management virtual void SetInputFocus( IUIPanel *pPanel, bool bScrollParentToFit, bool bChangeContextIfNeeded ) = 0; virtual bool SetInputFocusContext( IUIPanel *pPanelInContext ) = 0; virtual void PopInputContext() = 0; virtual IUIPanel *GetInputFocusContext() = 0; virtual IUIPanel *GetInputFocus() = 0; virtual IUIPanel *GetMouseHover() = 0; virtual void PanelDeleted( IUIPanel *pPanel, IUIPanel *pParent ) = 0; // input hooks virtual void HookPanelInput( IUIPanel *pPanel, IInputCapture *pInputCapture ) = 0; virtual void RemovePanelInputHook( IUIPanel *pPanel, IInputCapture *pInputCapture ) = 0; // set this panel to always (or stop) getting MouseMove events virtual void AddMouseTrackingPanel( IUIPanel *pPanel ) = 0; virtual void RemoveMouseTrackingPanel( IUIPanel *pPanel ) = 0; // Are we currently inside a set input focus call virtual bool BInSetInputFocusTraverse() = 0; // Queue a panel focus event to occur once we finish with setting input focus virtual void QueuePanelFocusEvent( IUIPanel *pPanel, CPanoramaSymbol symPanelEvent ) = 0; // reset any mouse movement count as we just hid the cursor virtual void ResetMouseMoveCount() = 0; // Get focus panel at time of last mouse down virtual IUIPanel *GetFocusOnLastMouseDown() = 0; }; // // Handles key/mouse/gamepad input and dispatches to appropriate panels // class IUIInput { public: virtual void Initialize( IUISettings *pSettings ) = 0; // Not ifdef'd or specific to windows. v_key ended up as a common // denominator in lots of code (overlay as an example) // 0x00 for error in mapping. There is no 0x00 VKEY virtual uint16 KeyCodeToWindowsVKey( const KeyCode inKey ) = 0; // KEY_NONE will come back on error. virtual KeyCode WindowsVKeyToKeyCode( uint16 inKey ) = 0; #ifdef SOURCE2_PANORAMA virtual ButtonCode_t KeyCodeToButtonCode( const KeyCode inKey ) = 0; virtual ButtonCode_t MouseCodeToButtonCode( const MouseCode inKey ) = 0; #endif // kb/mouse input virtual bool InputEvent( InputMessage_t &msg ) = 0; // used to capture all input virtual void SetInputCapture( IInputCapture *pCapture ) = 0; virtual void ReleaseInputCapture( IInputCapture *pCapture ) = 0; virtual CUtlVector< IInputCapture * > &GetInputCapture() = 0; // Checks whether gamepads are connected virtual int GetNumGamepadsConnected() const = 0; // did any gamepad have input since we last asked virtual bool BWasGamepadOrSteamControllerActive() = 0; // flags to tell steam controller layer which buttons to treat as mouse and not disable cursor on seeing virtual void SetSteamPadButtonsToTreatAsMouse( uint64 ulButtonMask ) = 0; // if a gamepad is connected then its friendly name virtual const char *PchGamePadName() = 0; // return true if we are emulating a gamepad using a simple joystick, so we have less input functionality available virtual bool BEmulatingGamePadWithJoystick() = 0; // helper for gamepad codes, returns values that are inside the deadzone for this joystick virtual float GetDeadZoneValue( GamePadCode code ) = 0; // translate an event into the gamepad key bound to it, XK_NULL if not bound virtual const GamePadCode GetGamePadBindForEvent( const char *pchEvent, const IUIPanel *pFromPanel ) = 0; // is capslock on virtual bool BIsCapsLockOn() = 0; // If we're trying to show help text for a controller, which type of controller is most relevant (ie., most recently // used, exists, etc.)? You probably don't want to call this directly but instead listen for ActiveControllerTypeChanged. virtual EActiveControllerType GetActiveControllerType() const = 0; // Get count of actively connected Steam controllers virtual uint32 GetSteamControllerCount() const = 0; // Get the time a steam controller was last assigned/used virtual float GetLastSteamControllerActiveTime() const = 0; // Get the time a non-steam controller was last assigned/used virtual float GetLastGamePadControllerActiveTime() const = 0; // Get the ID of the steam controller currently sending events to the window virtual int GetLastSteamControllerActiveIndex() const = 0; // Pulse haptic feedback on active gamepad/steam controller if supported virtual void PulseActiveControllerHaptic( IUIEngine::EHapticFeedbackPosition ePosition, IUIEngine::EHapticFeedbackStrength eStrength ) = 0; // Is finger actively down on steam controller right pad? Probably means mouse emulation in use. virtual bool BIsFingerDownOnSteamControllerRightPad() const = 0; // Register a file path to look for keybindings virtual void RegisterKeyBindingsFile( const char *pszFilePath ) = 0; // Force a reload of the keybindings virtual void ReloadKeyBindings() = 0; // Private APIs for remote gamepad input, called on a separate network thread virtual void RemoteGamepadAttached( int nGamepadID ) = 0; virtual void RemoteGamepadDetached( int nGamepadID ) = 0; virtual void SetRemoteGamepadAxis( int nGamepadID, int nAxis, int nValue ) = 0; virtual void SetRemoteGamepadButton( int nGamepadID, int nButton, int nValue ) = 0; // Turn off whatever (wireless) controller was last active virtual void TurnOffActiveController() = 0; // Get gamepad code value from textual name for config files, event code, etc virtual panorama::GamePadCode GamePadCodeFromName( const char * pchGamePadCode ) = 0; // Check if two gamepad codes are the 'same' button but on different vendor devices virtual bool BIsGamePadCodeEquivalentIgnoringVendor( GamePadCode a, GamePadCode b ) = 0; }; } // namespace panorama #endif // IUIINPUT_H