1 /**
2  * Defines the static Input class, which is responsible for handling all keyboard/mouse/controller interactions.
3  */
4 module utility.input;
5 import utility.config, utility.filepath, utility.output;
6 
7 import yaml;
8 import std.typecons, std.conv;
9 
10 final abstract class Input
11 {
12 public static:
13 	/**
14 	 * Function called when key event triggers.
15 	 */
16 	alias void delegate( uint, bool ) KeyEvent;
17 	alias void delegate( uint ) KeyStateEvent;
18 
19 	/**
20 	 * Processes Config/Input.yml and pulls input string bindings.
21 	 */
22 	final void initialize()
23 	{
24 		auto bindings = Config.loadYaml( FilePath.Resources.InputBindings );
25 
26 		foreach( key; keyBindings.keys )
27 			keyBindings.remove( key );
28 
29 		foreach( string name, Node bind; bindings )
30 		{
31 			log( OutputType.Info, "Binding ", name );
32 
33 			if( bind.isScalar )
34 			{
35 				keyBindings[ name ] = bind.get!Keyboard;
36 			}
37 			else if( bind.isSequence )
38 			{
39 				foreach( Node child; bind )
40 				{
41 					try
42 					{
43 						keyBindings[ name ] = child.get!Keyboard;
44 					}
45 					catch
46 					{
47 						log( OutputType.Error, "Failed to parse keybinding for input ", name );
48 					}
49 				}
50 			}
51 			else if( bind.isMapping )
52 			{
53 				foreach( string type, Node value; bind )
54 				{
55 					final switch( type )
56 					{
57 						case "Keyboard":
58 							try
59 							{
60 								keyBindings[ name ] = value.get!Keyboard;
61 							}
62 							catch
63 							{
64 								try
65 								{
66 									keyBindings[ name ] = value.get!string.to!Keyboard;
67 								}
68 								catch
69 								{
70 									log( OutputType.Error, "Failed to parse keybinding for input ", name );
71 								}
72 							}
73 
74 							break;
75 					}
76 				}
77 			}
78 		}
79 	}
80 
81 	/**
82 	 * Updates the key states, and calls all key events.
83 	 */
84 	final void update()
85 	{
86 		auto diff = staging - current;
87 
88 		previous = current;
89 		current = staging;
90 		staging.reset();
91 
92 		foreach( state; diff )
93 			if( auto keyEvent = state[ 0 ] in keyEvents )
94 				foreach( event; *keyEvent )
95 					event( state[ 0 ], state[ 1 ] );
96 	}
97 
98 	/**
99 	 * Add an event to be fired when the given key changes.
100 	 * 
101 	 * Params:
102 	 * 		keyCode =	The code of the key to add the event to.
103 	 * 		func =		The function to call when the key state changes.
104 	 */
105 	final void addKeyEvent( uint keyCode, KeyEvent func )
106 	{
107 		keyEvents[ keyCode ] ~= func;
108 	}
109 
110 	/**
111 	 * Add a key event only when the key is down.
112 	 */
113 	final void addKeyDownEvent( uint keyCode, KeyStateEvent func )
114 	{
115 		keyEvents[ keyCode ] ~= ( uint keyCode, bool newState ) { if( newState ) func( newState ); };
116 	}
117 
118 	/**
119 	 * Add a key event only when the key is up.
120 	 */
121 	final void addKeyUpEvent( uint keyCode, KeyStateEvent func )
122 	{
123 		keyEvents[ keyCode ] ~= ( uint keyCode, bool newState ) { if( !newState ) func( keyCode ); };
124 	}
125 
126 	/**
127 	 * Check if a given key is down.
128 	 * 
129 	 * Params:
130 	 * 		keyCode =		The code of the key to check.
131 	 * 		checkPrevious =	Whether or not to make sure the key was down last frame.
132 	 */
133 	final bool isKeyDown( uint keyCode, bool checkPrevious = false )
134 	{
135 		return current[ keyCode ] && ( !checkPrevious || previous[ keyCode ] );
136 	}
137 
138 	/**
139 	 * Check if a given key is up.
140 	 * 
141 	 * Params:
142 	 * 		keyCode =		The code of the key to check.
143 	 * 		checkPrevious =	Whether or not to make sure the key was up last frame.
144 	 */
145 	final bool isKeyUp( uint keyCode, bool checkPrevious = false )
146 	{
147 		return !current[ keyCode ] && ( !checkPrevious || !previous[ keyCode ] );
148 	}
149 
150 	/**
151 	 * Sets the state of the key to be assigned at the beginning of next frame.
152 	 * Should only be called from a window controller.
153 	 */
154 	final void setKeyState( uint keyCode, bool newState )
155 	{
156 		staging[ keyCode ] = newState;
157 	}
158 
159 	/**
160 	 * Gets the state of a string-bound input.
161 	 *
162 	 * Params:
163 	 *		input =			The input to check for.
164 	 * 		checkPrevious =	Whether or not to make sure the key was up last frame.
165 	 */
166 	final T getState( T = bool )( string input, bool checkPrevious = false ) if( is( T == bool ) /*|| is( T == float )*/ )
167 	{
168 		static if( is( T == bool ) )
169 		{
170 			if( input in keyBindings )
171 			{
172 				return isKeyDown( keyBindings[ input ], checkPrevious );
173 			}
174 			else
175 			{
176 				throw new Exception( "Input " ~ input ~ " not bound." );
177 			}
178 		}
179 		/*else static if( is( T == float ) )
180 		{
181 
182 		}*/
183 	}
184 
185 private:
186 	Keyboard[ string ] keyBindings;
187 
188 	KeyEvent[][ uint ] keyEvents;
189 
190 	KeyState current;
191 	KeyState previous;
192 	KeyState staging;
193 
194 	struct KeyState
195 	{
196 	public:
197 		enum TotalSize = 256u;
198 		enum ElementSize = uint.sizeof;
199 		enum Split = TotalSize / ElementSize;
200 
201 		uint[ Split ] keys;
202 
203 		ref KeyState opAssign( const ref KeyState other )
204 		{
205 			for( uint ii = 0; ii < Split; ++ii )
206 				keys[ ii ] = other.keys[ ii ];
207 
208 			return this;
209 		}
210 
211 		bool opIndex( size_t keyCode ) const
212 		{
213 			return ( keys[ keyCode / ElementSize ] & getBitAtIndex( keyCode ) ) != 0;
214 		}
215 
216 		bool opIndexAssign( bool newValue, size_t keyCode )
217 		{
218 			keys[ keyCode / ElementSize ] = getBitAtIndex( keyCode ) & uint.max;
219 			return newValue;
220 		}
221 
222 		Tuple!( uint, bool )[] opBinary( string Op : "-" )( const ref KeyState other )
223 		{
224 			Tuple!( uint, bool )[] differences;
225 
226 			for( uint ii = 0; ii < TotalSize; ++ii )
227 				if( this[ ii ] != other[ ii ] )
228 					differences ~= Tuple!( uint, bool )( ii, this[ ii ] );
229 
230 			return differences;
231 		}
232 
233 		void reset()
234 		{
235 			for( uint ii = 0; ii < Split; ++ii )
236 				keys[ ii ] = 0;
237 		}
238 
239 	private:
240 		static uint getBitAtIndex( size_t keyCode )
241 		{
242 			return 1 << ( keyCode % Split );
243 		}
244 	}
245 }
246 
247 /**
248  * Virtual key codes.
249  *
250  * From: http://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx
251  */
252 enum Keyboard: uint
253 {
254 	MouseLeft	= 0x01, /// Left mouse button
255 	MouseRight	= 0x02, /// Right mouse button
256 	Cancel		= 0x03, /// Control-break
257 	MouseMiddle	= 0x04, /// Middle mouse button
258 	XButton1	= 0x05, /// X1 mouse button
259 	XButton2	= 0x06, /// X2 mouse button
260 	//Unused	= 0x07,
261 	Backspace	= 0x08, /// Backspace key
262 	Tab			= 0x09, /// Tab key
263 	//Reserved	= 0x0A-0x0B,
264 	Clear		= 0x0C, /// Clear key
265 	Return		= 0x0D, /// Enter key
266 	//Undefined	= 0x0E-0x0F
267 	Shift		= 0x10, /// Shift key
268 	Control		= 0x11, /// Control key
269 	Alt			= 0x12, /// Menu/alt key
270 	Pause		= 0x13, /// Pause key
271 	CapsLock	= 0x14, /// Capital/Caps Lock key
272 	//Who Cares	= 0x15-0x1A,
273 	Escape		= 0x1B, /// Escape key
274 	//Who Cares	= 0x1C-0x1F
275 	Space		= 0x20, /// Space bar
276 	PageUp		= 0x21, /// Page Up/Prior key
277 	PageDown	= 0x22, /// Page Down/Next key
278 	End			= 0x23, /// End key
279 	Home		= 0x24, /// Home key
280 	Left		= 0x25, /// Left arrow key
281 	Up			= 0x26, /// Up arrow key
282 	Right		= 0x27, /// Right arrow key
283 	Down		= 0x28, /// Down arrow key
284 	Select		= 0x29, /// Select key
285 	Print		= 0x2A, /// Print key
286 	Execute		= 0x2B, /// Execute key
287 	PrintScreen	= 0x2C, /// Print Screen/Snapshot key
288 	Insert		= 0x2D, /// Insert key
289 	Delete		= 0x2E, /// Delete key
290 	Help		= 0x2F, /// Help key
291 	Keyboard0	= 0x30, /// 0 key
292 	Keyboard1	= 0x31, /// 1 key
293 	Keyboard2	= 0x32, /// 2 key
294 	Keyboard3	= 0x33, /// 3 key
295 	Keyboard4	= 0x34, /// 4 key
296 	Keyboard5	= 0x35, /// 5 key
297 	Keyboard6	= 0x36, /// 6 key
298 	Keyboard7	= 0x37, /// 7 key
299 	Keyboard8	= 0x38, /// 8 key
300 	Keyboard9	= 0x39, /// 9 key
301 	//Unused	= 0x3A-0x40
302 	A			= 0x41, /// A key
303 	B			= 0x42, /// B key
304 	C			= 0x43, /// C key
305 	D			= 0x44, /// D key
306 	E			= 0x45, /// E key
307 	F			= 0x46, /// F key
308 	G			= 0x47, /// G key
309 	H			= 0x48, /// H key
310 	I			= 0x49, /// I key
311 	J			= 0x4A, /// J key
312 	K			= 0x4B, /// K key
313 	L			= 0x4C, /// L key
314 	M			= 0x4D, /// M key
315 	N			= 0x4E, /// N key
316 	O			= 0x4F, /// O key
317 	P			= 0x50, /// P key
318 	Q			= 0x51, /// Q key
319 	R			= 0x52, /// R key
320 	S			= 0x53, /// S key
321 	T			= 0x54, /// T key
322 	U			= 0x55, /// U key
323 	V			= 0x56, /// V key
324 	W			= 0x57, /// W key
325 	X			= 0x58, /// X key
326 	Y			= 0x59, /// Y key
327 	Z			= 0x5A, /// Z key
328 	WindowsLeft	= 0x5B, /// Left windows key
329 	WindowsRight= 0x5C, /// Right windows key
330 	Apps		= 0x5D, /// Applications key
331 	//Reserved	= 0x5E
332 	Sleep		= 0x5F, /// Sleep key
333 	Numpad0		= 0x60, /// 0 key
334 	Numpad1		= 0x61, /// 1 key
335 	Numpad2		= 0x62, /// 2 key
336 	Numpad3		= 0x63, /// 3 key
337 	Numpad4		= 0x64, /// 4 key
338 	Numpad5		= 0x65, /// 5 key
339 	Numpad6		= 0x66, /// 6 key
340 	Numpad7		= 0x67, /// 7 key
341 	Numpad8		= 0x68, /// 8 key
342 	Numpad9		= 0x69, /// 9 key
343 	Multiply	= 0x6A, /// Multiply key
344 	Add			= 0x6B, /// Addition key
345 	Separator	= 0x6C, /// Seperator key
346 	Subtract	= 0x6D, /// Subtraction key
347 	Decimal		= 0x6E, /// Decimal key
348 	Divide		= 0x6F, /// Division key
349 	F1			= 0x70, /// Function 1 key
350 	F2			= 0x71, /// Function 2 key
351 	F3			= 0x72, /// Function 3 key
352 	F4			= 0x73, /// Function 4 key
353 	F5			= 0x74, /// Function 5 key
354 	F6			= 0x75, /// Function 6 key
355 	F7			= 0x76, /// Function 7 key
356 	F8			= 0x77, /// Function 8 key
357 	F9			= 0x78, /// Function 9 key
358 	F10			= 0x79, /// Function 10 key
359 	F11			= 0x7A, /// Function 11 key
360 	F12			= 0x7B, /// Function 12 key
361 	F13			= 0x7C, /// Function 13 key
362 	F14			= 0x7D, /// Function 14 key
363 	F15			= 0x7E, /// Function 15 key
364 	F16			= 0x7F, /// Function 16 key
365 	F17			= 0x80, /// Function 17 key
366 	F18			= 0x81, /// Function 18 key
367 	F19			= 0x82, /// Function 19 key
368 	F20			= 0x83, /// Function 20 key
369 	F21			= 0x84, /// Function 21 key
370 	F22			= 0x85, /// Function 22 key
371 	F23			= 0x86, /// Function 23 key
372 	F24			= 0x87, /// Function 24 key
373 	//Unused	= 0x88-0x8F,
374 	NumLock		= 0x90, /// Num Lock key
375 	ScrollLock	= 0x91, /// Scroll Lock key
376 	//OEM		= 0x92-0x96,
377 	//Unused	= 0x97-0x9F,
378 	ShiftLeft	= 0xA0, /// Left shift key
379 	ShiftRight	= 0xA1, /// Right shift key
380 	ControlLeft	= 0xA2, /// Left control key
381 	ControlRight= 0xA3, /// Right control key
382 	AltLeft		= 0xA4, /// Left Alt key
383 	AltRight	= 0xA5, /// Right Alt key
384 }