//===== Copyright 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // // $NoKeywords: $ // //===========================================================================// #ifndef INPUTSYSTEM_H #define INPUTSYSTEM_H #ifdef _WIN32 #pragma once #endif #define DONT_DEFINE_DWORD #include "platform.h" #include "basetypes.h" #ifdef PLATFORM_WINDOWS_PC #define OEMRESOURCE //for OCR_* cursor junk #define _WIN32_WINNT 0x502 #include #include #include "xbox/xboxstubs.h" #include "../../dx9sdk/include/XInput.h" #endif #if defined( _WIN32 ) && defined( USE_SDL ) #include "appframework/ilaunchermgr.h" #endif #if defined(PLATFORM_POSIX) && !defined(_PS3) #ifdef PLATFORM_OSX #define DWORD DWORD #define CARBON_WORKAROUND #include #include #include #include #include #include #include #include #include #undef DWORD #else typedef char xKey_t; #endif // OSX #include "posix_stubs.h" #endif // POSIX #include "appframework/ilaunchermgr.h" #include "inputsystem/iinputsystem.h" #include "tier2/tier2.h" #ifdef _PS3 #include "ps3/ps3_platform.h" #include "ps3/ps3_win32stubs.h" #include "ps3/ps3_core.h" #include "ps3/ps3stubs.h" #include #endif #include "tier1/UtlStringMap.h" #include "inputsystem/ButtonCode.h" #include "inputsystem/AnalogCode.h" #include "bitvec.h" #include "tier1/utlvector.h" #include "tier1/utlflags.h" #include "input_device.h" #include "steam/steam_api.h" #if defined( _X360 ) #include "xbox/xbox_win32stubs.h" #include "xbox/xbox_console.h" #endif enum { INPUT_TYPE_GENERIC_JOYSTICK = 0, INPUT_TYPE_STEAMCONTROLLER, }; //----------------------------------------------------------------------------- // Implementation of the input system //----------------------------------------------------------------------------- class CInputSystem : public CTier2AppSystem< IInputSystem > { typedef CTier2AppSystem< IInputSystem > BaseClass; public: // Constructor, destructor CInputSystem(); virtual ~CInputSystem(); // Inherited from IAppSystem virtual InitReturnVal_t Init(); virtual bool Connect( CreateInterfaceFn factory ); virtual void Shutdown(); // Inherited from IInputSystem virtual void AttachToWindow( void* hWnd ); virtual void DetachFromWindow( ); virtual void EnableInput( bool bEnable ); virtual void EnableMessagePump( bool bEnable ); virtual int GetPollTick() const; virtual void PollInputState( bool bIsInGame = false ); virtual bool IsButtonDown( ButtonCode_t code ) const; virtual int GetButtonPressedTick( ButtonCode_t code ) const; virtual int GetButtonReleasedTick( ButtonCode_t code ) const; virtual int GetAnalogValue( AnalogCode_t code ) const; virtual int GetAnalogDelta( AnalogCode_t code ) const; virtual int GetEventCount() const; virtual bool MotionControllerActive() const; virtual Quaternion GetMotionControllerOrientation() const; virtual float GetMotionControllerPosX() const; virtual float GetMotionControllerPosY() const; virtual int GetMotionControllerDeviceStatus() const; virtual uint64 GetMotionControllerDeviceStatusFlags() const; virtual void SetMotionControllerDeviceStatus( int nStatus ); virtual void SetMotionControllerCalibrationInvalid( void ); virtual void StepMotionControllerCalibration( void ); virtual void ResetMotionControllerScreenCalibration( void ); virtual const InputEvent_t* GetEventData( ) const; virtual void PostUserEvent( const InputEvent_t &event ); virtual int GetJoystickCount() const; virtual void EnableJoystickInput( int nJoystick, bool bEnable ); virtual void EnableJoystickDiagonalPOV( int nJoystick, bool bEnable ); virtual void SampleDevices( void ); virtual void SetRumble( float fLeftMotor, float fRightMotor, int userId ); virtual void StopRumble( int userId = INVALID_USER_ID ); virtual void ResetInputState( void ); virtual const char *ButtonCodeToString( ButtonCode_t code ) const; virtual const char *AnalogCodeToString( AnalogCode_t code ) const; virtual ButtonCode_t StringToButtonCode( const char *pString ) const; virtual AnalogCode_t StringToAnalogCode( const char *pString ) const; virtual ButtonCode_t VirtualKeyToButtonCode( int nVirtualKey ) const; virtual int ButtonCodeToVirtualKey( ButtonCode_t code ) const; virtual ButtonCode_t ScanCodeToButtonCode( int lParam ) const; virtual void SleepUntilInput( int nMaxSleepTimeMS ); virtual int GetPollCount() const; virtual void SetCursorPosition( int x, int y ); void GetRawMouseAccumulators( int& accumX, int& accumY ); virtual void GetCursorPosition( int *pX, int *pY ); virtual void SetMouseCursorVisible( bool bVisible ); virtual void AddUIEventListener(); virtual void RemoveUIEventListener(); virtual PlatWindow_t GetAttachedWindow() const; virtual InputCursorHandle_t GetStandardCursor( InputStandardCursor_t id ); virtual InputCursorHandle_t LoadCursorFromFile( const char *pFileName, const char *pPathID = NULL ); virtual void SetCursorIcon( InputCursorHandle_t hCursor ); virtual void EnableMouseCapture( PlatWindow_t hWnd ); virtual void DisableMouseCapture(); #ifdef PLATFORM_WINDOWS LRESULT WindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ); #elif defined(PLATFORM_OSX) // helper function for callbacks struct JoystickInfo_t; void HIDAddElement(CFTypeRef refElement, JoystickInfo_t &info ); #endif #ifdef _PS3 virtual void SetPS3CellPadDataHook( BCellPadDataHook_t hookFunc ); virtual void SetPS3CellPadNoDataHook( BCellPadNoDataHook_t hookFunc ); virtual void SetPS3StartButtonIdentificationMode(); virtual bool GetPS3CursorPos( int &x, int &y ); virtual void DisableHardwareCursor( void ); virtual void EnableHardwareCursor( void ); void ExitHardwareCursor( void ); #endif #if defined( USE_SDL ) virtual void DisableHardwareCursor( void ); virtual void EnableHardwareCursor( void ); #endif virtual void ResetCursorIcon(); // handles the connected input devices virtual InputDevice_t GetConnectedInputDevices( void ); // returns the bitfield of all connected devices virtual bool IsInputDeviceConnected( InputDevice_t device ); virtual void SetInputDeviceConnected( InputDevice_t device, bool connected = true ); virtual InputDevice_t IsOnlySingleDeviceConnected( void ); // handles the selected "current" primary input device virtual bool IsDeviceReadingInput( InputDevice_t device ) const; // returns whether the passed in device is the current device. Returns true if no current device is defined virtual InputDevice_t GetCurrentInputDevice( void ); // returns the enum referring to the one currently selected device virtual void SetCurrentInputDevice( InputDevice_t device ); virtual void ResetCurrentInputDevice( void ); // sets the input device to the platform default virtual void SampleInputToFindCurrentDevice( bool ); // looks for the next 'significant' button press to determine and set the current input device virtual bool IsSamplingForCurrentDevice( void ); void InitPlatfromInputDeviceInfo( void ); private: enum { STICK1_AXIS_X, STICK1_AXIS_Y, STICK2_AXIS_X, STICK2_AXIS_Y, MAX_STICKAXIS }; enum { INPUT_STATE_QUEUED = 0, INPUT_STATE_CURRENT, INPUT_STATE_COUNT, }; public: #if defined(PLATFORM_OSX) struct OSXInputValue_t { bool m_bSet; int m_MinVal; int m_MaxVal; int m_MinReport; int m_MaxReport; int m_Cookie; uint32 m_Usage; CFTypeRef m_RefElement; }; #define MAX_JOYSTICK_BUTTONS 32 #endif struct JoystickInfo_t { #if defined(PLATFORM_WINDOWS) || defined(_GAMECONSOLE) JOYINFOEX m_JoyInfoEx; #elif defined(PLATFORM_OSX) FFDeviceObjectReference m_FFInterface; IOHIDDeviceInterface **m_Interface; long usage; // from IOUSBHID Parser.h long usagePage; // from IOUSBHID Parser.h CInputSystem *m_pParent; bool m_bRemoved; bool m_bXBoxRumbleEnabled; OSXInputValue_t m_xaxis; OSXInputValue_t m_yaxis; OSXInputValue_t m_zaxis; OSXInputValue_t m_raxis; OSXInputValue_t m_uaxis; OSXInputValue_t m_vaxis; OSXInputValue_t m_POV; OSXInputValue_t m_Buttons[MAX_JOYSTICK_BUTTONS]; #elif defined(LINUX) void *m_pDevice; // Really an SDL_GameController*, NULL if not present. void *m_pHaptic; // Really an SDL_Haptic* float m_fCurrentRumble; bool m_bRumbleEnabled; #else #error #endif int m_nButtonCount; int m_nAxisFlags; int m_nDeviceId; bool m_bHasPOVControl; bool m_bDiagonalPOVControlEnabled; unsigned int m_nFlags; unsigned int m_nLastPolledButtons; unsigned int m_nLastPolledAxisButtons; unsigned int m_nLastPolledPOVState; unsigned long m_pLastPolledAxes[MAX_JOYSTICK_AXES]; }; private: struct xdevice_t { int userId; byte type; byte subtype; word flags; bool active; XINPUT_STATE states[2]; int newState; // track Xbox stick keys from previous frame xKey_t lastStickKeys[MAX_STICKAXIS]; int stickThreshold[MAX_STICKAXIS]; float stickScale[MAX_STICKAXIS]; int quitTimeout; int dpadLock; // rumble XINPUT_VIBRATION vibration; bool pendingRumbleUpdate; }; struct appKey_t { int repeats; int sample; }; struct InputState_t { // Analog states CBitVec m_ButtonState; int m_ButtonPressedTick[ BUTTON_CODE_LAST ]; int m_ButtonReleasedTick[ BUTTON_CODE_LAST ]; int m_pAnalogDelta[ ANALOG_CODE_LAST ]; int m_pAnalogValue[ ANALOG_CODE_LAST ]; CUtlVector< InputEvent_t > m_Events; bool m_bDirty; }; // Steam Controller struct steampad_t { steampad_t() { m_nHardwareIndex = 0; m_nJoystickIndex = INVALID_USER_ID; m_nLastPacketIndex = 0; active = false; memset( lastAnalogKeys, 0, sizeof( lastAnalogKeys ) ); } bool active; sKey_t lastAnalogKeys[MAX_STEAMPADAXIS]; appKey_t m_appSKeys[ SK_MAX_KEYS ]; // Hardware index and joystick index don't necessarily match // Joystick index will depend on the order of multiple initialized devices // Which could include other controller types // Hardware index should line up 1:1 with the order they're polled // and could change based on removing devices, unlike Joystick Index uint32 m_nHardwareIndex; int m_nJoystickIndex; uint32 m_nLastPacketIndex; }; steampad_t m_SteamControllerDevice[MAX_STEAM_CONTROLLERS]; uint32 m_unNumSteamControllerConnected; bool m_bControllerModeActive; int m_nControllerType[MAX_JOYSTICKS+MAX_STEAM_CONTROLLERS]; //Steam controllers start after this index. int m_nJoystickBaseline; public: // Initializes all Xbox controllers void InitializeXDevices( void ); // Opens an Xbox controller void OpenXDevice( xdevice_t* pXDevice, int userId ); // Closes an Xbox controller void CloseXDevice( xdevice_t* pXDevice ); // Samples the Xbox controllers void PollXDevices( void ); // Samples console mouse void PollXMouse(); // Samples console keyboard void PollXKeyboard(); // Helper function used by ReadXDevice to handle stick direction events void HandleXDeviceAxis( xdevice_t *pXDevice, int nAxisValue, xKey_t negativeKey, xKey_t positiveKey, int axisID ); // Samples an Xbox controller and queues input events void ReadXDevice( xdevice_t* pXDevice ); // Submits force feedback data to an Xbox controller void WriteToXDevice( xdevice_t* pXDevice ); // Sets rumble values for an Xbox controller void SetXDeviceRumble( float fLeftMotor, float fRightMotor, int userId ); #if !defined( _CERT ) && !defined(LINUX) CON_COMMAND_MEMBER_F( CInputSystem, "press_x360_button", PressX360Button, "Press the specified Xbox 360 controller button (lt, rt, st[art], ba[ck], lb, rb, a, b, x, y, l[eft], r[right], u[p], d[own])", 0 ); void PollPressX360Button( void ); uint32 m_press_x360_buttons[ 2 ]; #endif #if defined( _PS3 ) void PS3_PollKeyboard( void ); void PS3_PollMouse( void ); void PS3_XInputPollEverything( BCellPadDataHook_t hookFunc, BCellPadNoDataHook_t hookNoDataFunc ); DWORD PS3_XInputGetState( DWORD dwUserIndex, PXINPUT_STATE pState ); void HandlePS3SharpshooterButtons( void ); void HandlePS3Move( PXINPUT_STATE& pState ); virtual void PS3SetupHardwareCursor( void* image ); #endif void QueueMoveControllerRumble( float fRightMotor ); // Posts an Xbox key event, ignoring key repeats void PostXKeyEvent( int nUserId, xKey_t xKey, int nSample ); // Dispatches all joystick button events through the game's window procs void ProcessEvent( UINT uMsg, WPARAM wParam, LPARAM lParam ); // Initializes SteamControllers - Returns true if steam is running and finds controllers, otherwise false bool InitializeSteamControllers( void ); // Samples all Steam Controllers - returns true if active this frame bool PollSteamControllers( void ); // Initializes joysticks void InitializeJoysticks( void ); // Samples the joystick void PollJoystick( void ); // Update the joystick button state void UpdateJoystickButtonState( int nJoystick ); // Update the joystick POV control void UpdateJoystickPOVControl( int nJoystick ); // Record button state and post the event void JoystickButtonEvent( ButtonCode_t button, int sample ); bool IsSteamControllerActive() const; void SetSteamControllerMode( const char *pSteamControllerMode, const void *obj ); private: // Purpose: Get raw joystick sample along axis #if defined(LINUX) void AxisAnalogButtonEvent( ButtonCode_t buttonCode, bool state, int nLastSampleTick ); #elif defined(OSX) unsigned int AxisValue( JoystickAxis_t axis, JoystickInfo_t &info ); #else unsigned int AxisValue( JoystickAxis_t axis, JOYINFOEX& ji ); #endif // Chains the window message to the previous wndproc LRESULT ChainWindowMessage( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ); // Post an event to the queue void PostEvent( int nType, int nTick, int nData = 0, int nData2 = 0, int nData3 = 0 ); // Deals with app deactivation (sends a bunch of button released messages) void ActivateInputSystem( bool bActivated ); // Determines all mouse button presses int ButtonMaskFromMouseWParam( WPARAM wParam, ButtonCode_t code = BUTTON_CODE_INVALID, bool bDown = false ) const; // Updates the state of all mouse buttons void UpdateMouseButtonState( int nButtonMask, ButtonCode_t dblClickCode = BUTTON_CODE_INVALID ); // Copies the input state record over void CopyInputState( InputState_t *pDest, const InputState_t &src, bool bCopyEvents ); // Post an button press/release event to the queue void PostButtonPressedEvent( InputEventType_t nType, int nTick, ButtonCode_t scanCode, ButtonCode_t virtualCode ); void PostButtonReleasedEvent( InputEventType_t nType, int nTick, ButtonCode_t scanCode, ButtonCode_t virtualCode ); // Release all buttons void ReleaseAllButtons( int nFirstButton = 0, int nLastButton = BUTTON_CODE_LAST - 1 ); // Zero analog state void ZeroAnalogState( int nFirstState, int nLastState ); // Converts xbox keys to button codes ButtonCode_t XKeyToButtonCode( int nUserId, int nXKey ) const; // Converts SteamController keys to button codes ButtonCode_t SKeyToButtonCode( int nUserId, int nXKey ) const; // Computes the sample tick int ComputeSampleTick(); // Clears the input state, doesn't generate key-up messages void ClearInputState( bool bPurgeState ); // Called for mouse move events. Sets the current x and y and posts events for the mouse moving. void UpdateMousePositionState( InputState_t &state, short x, short y ); // Should we generate UI events? bool ShouldGenerateUIEvents() const; // Generates LocateMouseClick messages void LocateMouseClick( LPARAM lParam ); // Initializes, shuts down cursors void InitCursors(); void ShutdownCursors(); #ifdef WIN32 void PollInputState_Windows(); #endif // Poll input state for different OSes. #if defined( PLATFORM_OSX ) void PollInputState_OSX(); void HIDGetElementInfo( CFTypeRef refElement, OSXInputValue_t &input ); bool HIDBuildDevice( io_object_t ioHIDDeviceObject, JoystickInfo_t &info ); bool HIDCreateOpenDeviceInterface( io_object_t hidDevice, JoystickInfo_t &info ); void HIDGetDeviceInfo( io_object_t hidDevice, CFMutableDictionaryRef hidProperties, JoystickInfo_t &info ); void HIDGetElements( CFTypeRef refElementCurrent, JoystickInfo_t &info ); void HIDGetCollectionElements( CFMutableDictionaryRef deviceProperties, JoystickInfo_t &info ); void HIDDisposeDevice( JoystickInfo_t &info ); int HIDGetElementValue( JoystickInfo_t &info, OSXInputValue_t &value ); int HIDScaledCalibratedValue( JoystickInfo_t &info, OSXInputValue_t &value ); void HIDSortJoystickButtons( JoystickInfo_t &info ); #elif defined(LINUX) public: void PollInputState_Linux(); void JoystickHotplugAdded( int joystickIndex ); void JoystickHotplugRemoved( int joystickId ); void JoystickButtonPress( int joystickId, int button ); // button is a SDL_CONTROLLER_BUTTON; void JoystickButtonRelease( int joystickId, int button ); // same as above. void JoystickAxisMotion( int joystickId, int axis, int value ); #endif private: #if defined( USE_SDL ) || defined( OSX ) ILauncherMgr *m_pLauncherMgr; #endif WNDPROC m_ChainedWndProc; HWND m_hAttachedHWnd; HWND m_hLastIMEHWnd; bool m_bEnabled; bool m_bPumpEnabled; bool m_bIsPolling; bool m_bIMEComposing; bool m_bIsInGame; // Current button state InputState_t m_InputState[INPUT_STATE_COUNT]; DWORD m_StartupTimeTick; int m_nLastPollTick; int m_nLastSampleTick; int m_nPollCount; // Mouse wheel hack UINT m_uiMouseWheel; // Joystick info CUtlFlags m_JoysticksEnabled; int m_nJoystickCount; bool m_bXController; bool m_bSteamController; float m_flLastSteamControllerInput; float m_flLastControllerPollTime; public: JoystickInfo_t m_pJoystickInfo[ MAX_JOYSTICKS ]; private: // Xbox controller info appKey_t m_appXKeys[ XUSER_MAX_COUNT ][ XK_MAX_KEYS ]; xdevice_t m_XDevices[ XUSER_MAX_COUNT ]; // Used to determine whether to generate UI events int m_nUIEventClientCount; // raw mouse input bool m_bRawInputSupported; int m_mouseRawAccumX, m_mouseRawAccumY; // Current mouse capture window PlatWindow_t m_hCurrentCaptureWnd; // For the 'SleepUntilInput' feature HANDLE m_hEvent; // Cursors, foiled again! InputCursorHandle_t m_pDefaultCursors[ INPUT_CURSOR_COUNT ]; CUtlStringMap< InputCursorHandle_t > m_UserCursors; CSysModule *m_pXInputDLL; CSysModule *m_pRawInputDLL; // NVNT falcon module CSysModule *m_pNovintDLL; private: bool m_bCursorVisible; bool m_bMotionControllerActive; Quaternion m_qMotionControllerOrientation; float m_fMotionControllerPosX; float m_fMotionControllerPosY; Vector m_vecMotionControllerPos; int m_nMotionControllerStatus; uint64 m_nMotionControllerStatusFlags; public: InputCursorHandle_t m_hCursor; #ifdef _PS3 BCellPadDataHook_t m_pPS3CellPadDataHook; BCellPadNoDataHook_t m_pPS3CellNoPadDataHook; bool m_PS3KeyboardConnected; bool m_PS3MouseConnected; #endif // describes all connected devices. A bitmask of InputDevice entries InputDevice_t m_currentlyConnectedInputDevices; // describes the current default input device InputDevice_t m_currentInputDevice; // number of different input devices on this platform bool m_setCurrentInputDeviceOnNextButtonPress; }; // Should we generate UI events? inline bool CInputSystem::ShouldGenerateUIEvents() const { return m_nUIEventClientCount > 0; } #endif // INPUTSYSTEM_H