summaryrefslogtreecommitdiff
path: root/public/panorama/input/iuiinput.h
blob: df362e1616e4f623888c8fc857405fe5da3faa76 (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
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
//=========== 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