summaryrefslogtreecommitdiff
path: root/inputsystem/inputsystem.h
blob: 9a85148d149948e02b3d88a03f7c866e036e0b20 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: 
//
// $NoKeywords: $
//
//===========================================================================//
#ifndef INPUTSYSTEM_H
#define INPUTSYSTEM_H
#ifdef _WIN32
#pragma once
#endif


#ifdef WIN32
#if !defined( _X360 )
#define _WIN32_WINNT 0x502
#include <windows.h>
#include <zmouse.h>
#include "xbox/xboxstubs.h"
#include "../../dx9sdk/include/XInput.h"
#endif
#endif

#ifdef POSIX
#include "posix_stubs.h"
#endif // POSIX

#include "appframework/ilaunchermgr.h"

#include "inputsystem/iinputsystem.h"
#include "tier2/tier2.h"

#include "inputsystem/ButtonCode.h"
#include "inputsystem/AnalogCode.h"
#include "bitvec.h"
#include "tier1/utlvector.h"
#include "tier1/utlflags.h"

#if defined( _X360 )
#include "xbox/xbox_win32stubs.h"
#include "xbox/xbox_console.h"
#endif

#include "steam/steam_api.h"

//-----------------------------------------------------------------------------
// 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();
	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 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( void );
	virtual void ResetInputState( void );
	virtual void SetPrimaryUserId( int userId );
	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 );
#if defined( WIN32 ) && !defined ( _X360 )
	virtual void *GetHapticsInterfaceAddress() const;
#else
	virtual void *GetHapticsInterfaceAddress() const { return NULL;}	
#endif
	bool GetRawMouseAccumulators( int& accumX, int& accumY );
	virtual void SetConsoleTextMode( bool bConsoleTextMode );

	// Windows proc
	LRESULT WindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam );


private:
	enum
	{
		STICK1_AXIS_LEFT,
		STICK1_AXIS_RIGHT,
		STICK1_AXIS_DOWN,
		STICK1_AXIS_UP,
		STICK2_AXIS_LEFT,
		STICK2_AXIS_RIGHT,
		STICK2_AXIS_DOWN,
		STICK2_AXIS_UP,
		MAX_STICKAXIS
	};

	// track Xbox stick keys from previous frame
	enum
	{
		LASTKEY_STICK1_X,
		LASTKEY_STICK1_Y,
		LASTKEY_STICK2_X,
		LASTKEY_STICK2_Y,
		MAX_LASTKEY,
	};

	enum
	{
		INPUT_STATE_QUEUED = 0,
		INPUT_STATE_CURRENT,

		INPUT_STATE_COUNT,
	};

public:

	struct JoystickInfo_t
	{
		void *m_pDevice;  // Really an SDL_GameController*, NULL if not present.
		void *m_pHaptic;  // Really an SDL_Haptic*
		float m_fCurrentRumble;
		bool m_bRumbleEnabled;
		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];
	};

	struct xdevice_t
	{
		int					userId;
		byte				type;
		byte				subtype;
		word				flags;
		bool				active;
		XINPUT_STATE		states[2];
		int					newState;
		xKey_t				lastStickKeys[MAX_LASTKEY];
		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<BUTTON_CODE_LAST> 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;
	};

	// 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 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 );

	// 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 joysticks
	void InitializeJoysticks( void );

	// Shut down joysticks
	void ShutdownJoysticks( 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 );

#if defined( WIN32 ) && !defined ( _X360 )
	// NVNT attaches window to novint devices
	void AttachWindowToNovintDevices( void * hWnd );

	// NVNT detaches window from novint input
	void DetachWindowFromNovintDevices( void );

	// NVNT Initializes novint devices
	void InitializeNovintDevices( void );

	// NVNT Samples a novint device
	void PollNovintDevices( void );

	// NVNT Update the novint device button state
	void UpdateNovintDeviceButtonState( int nDevice );

	// NVNT Record button state and post the event
	void NovintDeviceButtonEvent( ButtonCode_t button, int sample );

	//Added called and set to true when binding input and set to false once bound
	void SetNovintPure( bool bPure );
#else
	void SetNovintPure( bool bPure ) {} // to satify the IInput virtual interface	
#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;

	// Computes the sample tick
	int ComputeSampleTick();

	// Clears the input state, doesn't generate key-up messages
	void ClearInputState();

	// 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 );

	// Initializes SteamControllers - Returns true if steam is running and finds controllers, otherwise false
	bool InitializeSteamControllers( void );

	// Returns number of connected Steam Controllers
	uint32 GetNumSteamControllersConnected();

	// Update and sample steam controllers
	void PollSteamControllers( void );

#if defined( PLATFORM_WINDOWS_PC )
	void PollInputState_Windows();
#endif

	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 );

	// Steam Controller
	void ReadSteamController( int iIndex );
	void PostKeyEvent( int iIndex, sKey_t sKey, int nSample );
	const int GetSteamPadDeadZone( ESteamPadAxis axis );
	bool IsSteamControllerConnected( void ) { return m_bSteamController; }
	bool IsSteamControllerActive( void );
	void ActivateSteamControllerActionSetForSlot( uint64 nSlot, GameActionSet_t eActionSet );
	ControllerActionSetHandle_t GetActionSetHandle( GameActionSet_t eActionSet );
	ControllerActionSetHandle_t GetActionSetHandle( const char* szActionSet );
	bool GetControllerStateForSlot( int nSlot );
	int GetSteamControllerIndexForSlot( int nSlot );
	bool GetRadialMenuStickValues( int nSlot, float &fX, float &fY );
	virtual ISteamController* SteamControllerInterface();
	bool InitializeSteamControllerActionSets();

	// Gets the action origin (i.e. which physical input) maps to the given action name
	virtual EControllerActionOrigin GetSteamControllerActionOrigin( const char* action, GameActionSet_t action_set );
	virtual EControllerActionOrigin GetSteamControllerActionOrigin( const char* action, ControllerActionSetHandle_t action_set_handle );

	// Maps a Steam Controller action origin to a string (consisting of a single character) in our SC icon font
	virtual const wchar_t*	GetSteamControllerFontCharacterForActionOrigin( EControllerActionOrigin origin );

	// Maps a Steam Controller action origin to a short text string (e.g. "X", "LB", "LDOWN") describing the control.
	// Prefer to actually use the icon font wherever possible.
	virtual const wchar_t* GetSteamControllerDescriptionForActionOrigin( EControllerActionOrigin origin );

	// Converts SteamController keys to button codes
	ButtonCode_t SKeyToButtonCode( int nUserId, int nXKey ) const;

	// This is called with "true" by dedicated server initialization (before calling Init) in order to
	// force us to skip initialization of Steam (which messes up dedicated servers).
	virtual void SetSkipControllerInitialization( bool bSkip )
	{
		m_bSkipControllerInitialization = bSkip;
	}

#if defined( USE_SDL )
	void PollInputState_Platform();

	ILauncherMgr *m_pLauncherMgr;
#endif

	WNDPROC m_ChainedWndProc;
	HWND m_hAttachedHWnd;
	bool m_bEnabled;
	bool m_bPumpEnabled;
	bool m_bIsPolling;

	// Current button state
	InputState_t m_InputState[INPUT_STATE_COUNT];

	// Current action set
	GameActionSet_t m_currentActionSet[STEAM_CONTROLLER_MAX_COUNT];

	DWORD m_StartupTimeTick;
	int m_nLastPollTick;
	int m_nLastSampleTick;
	int m_nPollCount;

	// Mouse wheel hack
	UINT m_uiMouseWheel;

	// Joystick info
	CUtlFlags<unsigned short> m_JoysticksEnabled;
	int m_nJoystickCount;
	bool m_bJoystickInitialized;
	bool m_bXController;
	JoystickInfo_t m_pJoystickInfo[ MAX_JOYSTICKS ];

	// 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;
	};

	float m_pRadialMenuStickVal[STEAM_CONTROLLER_MAX_COUNT][2];
	steampad_t m_Device[STEAM_CONTROLLER_MAX_COUNT];
	uint32 m_unNumConnected;
	float m_flLastSteamControllerInput;
	int m_nJoystickBaseline;
	int m_nControllerType[MAX_JOYSTICKS+STEAM_CONTROLLER_MAX_COUNT];

	bool m_bSteamController;						// true if the Steam Controller system has been initialized successfully (this doesn't mean one is actually connected necessarily)
	bool m_bSteamControllerActionsInitialized;		// true if our action sets and handles were successfully initialized (this doesn't mean a controller is necessarily connected, or that in-game client actions were initialized)
	bool m_bSteamControllerActive;					// true if our action sets and handles were successfully initialized *and* that at least one controller is actually connected and switched on.

#if defined( WIN32 ) && !defined ( _X360 )
	// NVNT Novint device info
	int m_nNovintDeviceCount;
	bool m_bNovintDevices;
#endif

	// Xbox controller info
	appKey_t	m_appXKeys[ XUSER_MAX_COUNT ][ XK_MAX_KEYS ];
	xdevice_t	m_XDevices[ XUSER_MAX_COUNT ];
	int			m_PrimaryUserId;

	// raw mouse input
	bool m_bRawInputSupported;
	int	 m_mouseRawAccumX, m_mouseRawAccumY;

	// For the 'SleepUntilInput' feature
	HANDLE m_hEvent;

	CSysModule   *m_pXInputDLL;
	CSysModule   *m_pRawInputDLL;
	
#if defined( WIN32 ) && !defined ( _X360 )
	// NVNT falcon module
	CSysModule	 *m_pNovintDLL;
#endif

	bool m_bConsoleTextMode;

public:
	// Steam API context for use by input system for access to steam controllers.
	CSteamAPIContext& SteamAPIContext() { return m_SteamAPIContext; }

private:
	CSteamAPIContext m_SteamAPIContext;
	bool m_bSkipControllerInitialization;
};

#endif // INPUTSYSTEM_H