summaryrefslogtreecommitdiff
path: root/public/panorama/textinput/textinput_daisywheel.h
blob: a523fc943602134165f7a54c83b2279facf6f428 (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
//=========== Copyright Valve Corporation, All rights reserved. ===============//
//
// Purpose: 
//=============================================================================//

#ifndef PANORAMA_TEXTINPUT_DAISYWHEEL_H
#define PANORAMA_TEXTINPUT_DAISYWHEEL_H

#include "panorama/textinput/textinput.h"
#include "panorama/controls/panel2d.h"
#include "panorama/controls/label.h"
#include "panorama/input/iuiinput.h"
#include "mathlib/beziercurve.h"
#include "tier1/utlptr.h"
#include "panorama/uischeduleddel.h"

namespace panorama
{

// Forward declaration
class CTextInputDaisyWheel;
class CTextEntry;
class ITextInputSuggest;
class CLabel;

//-----------------------------------------------------------------------------
// Purpose: Implementation of daisy wheel text input handler
//-----------------------------------------------------------------------------
class CTextInputDaisyWheel : public panorama::CTextInputHandler
{
	DECLARE_PANEL2D( CTextInputDaisyWheel, panorama::CPanel2D );

public:
	// Constructor
	CTextInputDaisyWheel( panorama::IUIWindow *pParent, const CTextInputHandlerSettings &settings, ITextInputControl *pTextControl );
	CTextInputDaisyWheel( panorama::CPanel2D *parent, const CTextInputHandlerSettings &settings, ITextInputControl *pTextControl );

	// Destructor
	~CTextInputDaisyWheel();

	// CTextInputHandler overrides
	virtual void OpenHandler() OVERRIDE;
	virtual void CloseHandlerImpl( bool bCommitText ) OVERRIDE;
	virtual ETextInputHandlerType_t GetType() OVERRIDE;
	virtual ITextInputControl *GetControlInterface() OVERRIDE;
	virtual void SuggestWord( const wchar_t *pwch, int ich ) OVERRIDE;
	virtual void SetYButtonAction( const char *pchLabel, IUIEvent *pEvent ) OVERRIDE;

	static void GetSupportedLanguages( CUtlVector<ELanguage> &vecLangs );
private:
	void Initialize( const CTextInputHandlerSettings &settings, ITextInputControl *pTextControl );

	// This isn't part of CTextInputHandler because currently there is no need to set this dynamically
	void SetMode( ETextInputMode_t mode );

	// CPanel2D overrides
	virtual bool OnGamePadUp( const panorama::GamePadData_t &code ) OVERRIDE;
	virtual bool OnGamePadDown( const panorama::GamePadData_t &code ) OVERRIDE;
	virtual bool OnGamePadAnalog( const panorama::GamePadData_t &code ) OVERRIDE;
	virtual bool OnKeyTyped( const KeyData_t &unichar ) OVERRIDE;
	virtual bool OnKeyDown( const KeyData_t &code ) OVERRIDE;
	virtual bool OnKeyUp( const KeyData_t &code ) OVERRIDE;

	//
	//	Daisy wheel input type
	//
	enum EDaisyInputType_t
	{
		k_EDaisyInputTypeABXY,		// ABXY layout has color buttons printing keys
		k_EDaisyInputTypeRS,		// RS layout requires Right Stick usage to print keys
		k_EDaisyInputTypePIN,		// Button map to numbers for secret PIN entry
	};

	//	Set daisy wheel type
	void SetDaisyInputType( EDaisyInputType_t eType );

	// Add an emoticon to the list of emoji this daisywheel will show
	// TODO: Currently not part of CTextInputHandler because emoticons need work
	void AddEmoticon( const char *szInsert, const char *szImageURL );
	void CommitEmoticons();

#ifdef DBGFLAG_VALIDATE
	void ValidateClientPanel( CValidator &validator, const tchar *pchName );
#endif

	// User wants to move focus to the next field on the page
	bool NextFocus();

	static const int k_cPetals = 8;										// # petals in flower (hardcoded for now)
	static const int k_cItemsPerPetal = 4;									// # letters visible on each petal, max
	static const int k_cItemsPerLayoutMax = k_cPetals * k_cItemsPerPetal;		// # letters total per layout, max

	struct Emoticon_t
	{
		CUtlString sType;
		CUtlString sImageURL;
	};

	//
	//	A single wheel layout configuration: name and UTF-8 sequences of characters
	//	Structure is allocated with more memory at the end of the structure, name and
	//	UTF-8 sequences follow this structure object
	//
	class CDaisyConfig
	{
	public:
		CDaisyConfig( const char *pchName ) : m_sName( pchName )
		{
		}

		// Get the name of wheel layout
		char const * GetName() const { return m_sName.String(); }

		// Get number of items in this wheel layout
		int GetNumItems() const { return m_cItems; }

		// Get a given item in this wheel layout, must be >= zero and < number of items
		// double the index, because each item is NUL terminated
		const char * GetItem( int idx ) const
		{
			if ( idx >= k_cItemsPerLayoutMax || idx < 0 )
			{
				Assert( false );
				return "";
			}

			return m_vecText.Base() + m_rgich[ idx ];
		}

		#ifdef DBGFLAG_VALIDATE
		void Validate( CValidator &validator, const tchar *pchName )
		{
			VALIDATE_SCOPE();
			ValidateObj( m_sName );
			ValidateObj( m_vecText );
		}
		#endif

		// name of this layout
		CUtlString m_sName;

		// Number of items in this wheel layout
		int m_cItems;

		// offsets into the text block for each item in this layout
		int m_rgich[ k_cItemsPerLayoutMax ];

		// block of text for this layout, UTF-8
		CUtlVector< char > m_vecText;
	};

	//	After configuration has been loaded and assigned walk through all
	//	controls and set their values to represent the loaded config
	void SetControlsFromConfiguration();

	// map the trigger inputs to a config
	enum EDaisyConfig_t
	{
		k_EDaisyConfigNone = -1,
		k_EDaisyConfigCaps,
		k_EDaisyConfigLetters,
		k_EDaisyConfigNumbers,
		k_EDaisyConfigSpecial,
		k_EDaisyConfigNumbersOnly,		
		k_EDaisyConfigPhoneNumber,
		k_EDaisyConfigSteamCodeChars,
		k_EDaisyConfigEmoji,
	};
	typedef CUtlMap< EDaisyConfig_t, CUtlPtr< CDaisyConfig >, int, CDefLess< EDaisyConfig_t > > MapConfigEntries_t;

	EDaisyConfig_t EDaisyConfigFromString( const char *pchValue );
	EDaisyConfig_t ConfigFromTriggerState( bool bLeftTrigger, bool bRightTrigger );

	// update the trigger legends based on the current trigger state
	void UpdateTriggerLegends();

	// moves controls to existing config (caps -> lowercase)
	void AdvanceControlsConfiguration( EDaisyConfig_t eConfig );

	//	Types a character from selected group's side of world: "E" | "W" | "N" | "S"
	bool TypeCharacterFromSide( char chSide );

	//	Types a given wide character into text entry
	bool TypeWchar( uchar16 wch );

	//	Simulates a key down event
	bool TypeKeyDown( panorama::KeyCode eCode );

	//	Loads configuration file for specified language
	bool LoadInputConfigurationFile( ELanguage language );

	//	Loads configuration file
	bool LoadInputConfigurationFile( const char *szConfig, const char *szConfigRootDir );

	//	Builds configuration structure based on buffer loaded from config file
	bool LoadConfigurationBuffer( char const *pszBase, MapConfigEntries_t *pmapConfigs );

	// Switch between most recent languages
	bool SwitchLanguage();
	bool ShowThisLanguage( ELanguage language );

	//	For a given config item determine which group and group side the item should be at
	void GetItemLocation( CDaisyConfig *pCfg, int iItem, char const *&szGroup, char const *&szItem );

	//	Get name of the group square indexed by -1|0|1 pair of x,y coordinates; returns side or wolrd like: "E" | "NE" | "N" | "NW" | etc.
	char const * GetGroupNameSq( int x, int y );

	//	Gets a sequential index of the group square indexed by -1|0|1 pair of x,y coordinates
	int GetGroupIdxSq( int x, int y );

	//	Gets the side of world name of group by its sequential index
	char const * GetGroup( int idxGroup );
	
	//	Gets the side of world name of item by its sequential index
	char const * GetSide( int idxSide );

	//	Process scheduled key repeat
	void ScheduleKeyRepeats( panorama::GamePadCode eCode );
	void CancelOutstandingRepeats() { ScheduleKeyRepeats( XK_NULL ); }

	void ScheduledKeyRepeatFunction();

	bool HandlePropertyTransitionEnd( const panorama::CPanelPtr< panorama::IUIPanel > &pPanel, CStyleSymbol sym );

	// Listen for focus lost
	bool HandleInputFocusLost( const panorama::CPanelPtr< panorama::IUIPanel > &ptrPanel );

	// events bound in window_keybinds.cfg
	bool ShowHideSettings();

	// settings events
	bool CancelSettings();

	// auto-suggestion
	void ShowSuggestion( const char *szPrefix, const char *szSuffix );
	void ClearSuggestionVisual()
	{
		ShowSuggestion( "", "" );
	}
	void ClearSuggestionState()
	{
		m_sSuggestion.Clear();
		ClearSuggestionVisual();
	}

	bool BCursorAtStartOfSentence();
	bool BConvertNextSpaceToPeriod();

	// Play sound for a give daisy wheel activity
	enum EDaisyAction_t
	{
		k_EDaisySound_ButtonA,
		k_EDaisySound_ButtonB,
		k_EDaisySound_ButtonX,
		k_EDaisySound_ButtonY,
		k_EDaisySound_KeySpacebar,
		k_EDaisySound_KeyBackspace,
		k_EDaisySound_KeyLeft,
		k_EDaisySound_KeyRight,
		k_EDaisySound_KeyHome,
		k_EDaisySound_KeyEnd,
		k_EDaisySound_FocusAreaChanged,
		k_EDaisySound_ConfigChanged,
		k_EDaisySound_FocusAreaCold,
		k_EDaisySound_PerformAutosuggest,
	};
	void PlayDaisyActionSound( EDaisyAction_t eAction );

	//	Function to handle gamepad data depending on daisy wheel settings
	typedef bool (CTextInputDaisyWheel::*PFNGamePadData)( const panorama::GamePadData_t &code );
	
	MapConfigEntries_t m_mapConfigEntries;		//	Processed configuration entries
	EDaisyConfig_t m_eConfigCurrent;			//	Current config, can be cycled with triggers
	bool m_bRestrictConfig;						//	if true, stick to current config (no changing layouts)

	panorama::CPanel2D *m_pStickPri;		// Primary stick control
	float m_flStickPriSelectOct[2];			// Selection octant angles (std: lo=M_PI/6, hi=M_PI/3)
	float m_flStickPriMoveScale[2];			// Scale for primary stick movement
	float m_flStickPriSelectDist[2];		// Selection distances
	float m_flStickPriSelectAngleSticky;	// Selection angle to stick to area
	float m_flStickPriColdTime;				// How long we need primary stick to remain cold
	int m_nSelectionGroup[2];				// Currently selected group

	panorama::CPanel2D *m_pStickSnd;		// Secondary stick control
	float m_flStickSndMoveScale[2];			// Scale for secondary stick movement
	float m_flStickSndSelectDist[2];		// Selection distances for secondary stick
	float m_flStickSndSelectAngleSticky;	// Selection angle for secondary stick to stick to area

	panorama::CLabel *m_pLang;				// Language legend label

	double m_flPickedItemTransitionTime;		// Time for picked item to highlight

	PFNGamePadData m_pfnOnGamePadDown;		// Current config for gamepad down
	PFNGamePadData m_pfnOnGamePadAnalog;	// Current config for gamepad analog

	// settings
	bool m_bDoubleSpaceToDotSpace;
	bool m_bAutoCaps;

	// Tracking doublespace = dot+space
	bool m_bOnlySpacesEnteredSinceBackspace;

	// Tracking trigger state for typing
	bool m_bTriggersDownState[2];			// Whether trigger is down

	// Tracking stick cold state
	double m_flTimeStickCold;				// When stick went into cold state (rolls when hot)

	// Tracking key repeats
	CCubicBezierCurve< Vector2D > m_repeatCurve;	// Curve for key repeats
	double m_repeatStartTime;					// Time when the key was initially pressed
	double m_repeatNextTime;						// Time when the key will repeat next
	panorama::GamePadCode m_repeatGamePadCode;	// Which key was pressed (low level, for key-up tracking)
	uint32 m_repeatCounter;						// How many key repeats have happened
	panorama::CUIScheduledDel m_repeatFunction;	// Scheduled function triggering key repeats

	// Stick processing routines
	bool OnGamePadAnalog_ProcessLeftStickForGroup( const panorama::GamePadData_t &code );
	bool OnGamePadAnalog_ProcessRightStickForSide( const panorama::GamePadData_t &code );
	bool OnGamePadAnalog_Trigger( const panorama::GamePadData_t &code );
	bool HandleTextInputDaisyWheelOnGamePadAnalogTriggersChanged();

	// ABXY handlers
	bool DaisyABXY_OnGamePadDown( const panorama::GamePadData_t &code );
	bool DaisyABXY_OnGamePadAnalog( const panorama::GamePadData_t &code );

	// RS handlers
	bool DaisyRS_OnGamePadDown( const panorama::GamePadData_t &code );
	bool DaisyRS_OnGamePadAnalog( const panorama::GamePadData_t &code );

	// PINpad handlers
	bool DaisyPIN_OnGamePadDown( const panorama::GamePadData_t & code );
	bool DaisyPIN_OnGamePadAnalog( const panorama::GamePadData_t &code );

	ELanguage m_language;						// currently loaded language

	ITextInputSuggest *m_psuggest;				// suggestion engine
	CUtlString m_sSuggestion;					// result of suggestion

	panorama::CLabel *m_plabelSuggestionPrefix;	// label containing prefix of current suggestion
	panorama::CLabel *m_plabelSuggestionSuffix;	// label containing prefix of current suggestion

	double m_flInputStartTime; // when did the user first start typing
	bool m_bUsedKeyboard; // true if the kb was used for ANY input
	bool m_bUsedGamepad; // true if the gamepad was used for ANY input

	ITextInputControl *m_pTextInputControl; // control interface for moving text input between a control and daisy wheel
	IUIEvent *m_pYbuttonAction; // the action to fire if the Y button is hit
	panorama::CLabel *m_pYButtonText; // label for ybutton text
	ETextInputMode_t m_mode;	// text input mode
	bool m_bDisplaySuggestions;	// If true, allow suggestions to be displayed

	// mode can disable specific footer sections
	bool m_bDisableRightTrigger;
	bool m_bDisableRightBumper;
	bool m_bDisableLeftTrigger;
	bool m_bDisableLanguageSelect;

	enum ERightStickPos 
	{
		k_RightStick_None,
		k_RightStick_Up,
		k_RightStick_Down,
		k_RightStick_Left,
		k_RightStick_Right,
	};
	ERightStickPos m_eSteamRightStickPos;
	Vector2D m_vecRightPadPos;

	CUtlVector< Emoticon_t > m_vecEmoji;
	bool m_bLoadedEmoji;
};

} // namespace panorama

#endif // PANORAMA_TEXTINPUT_DAISYWHEEL_H