1 module PixelPerfectEngine.system.inputHandler;
2 /*
3  * Copyright (C) 2015-2019, by Laszlo Szeremi under the Boost license.
4  *
5  * Pixel Perfect Engine, input module
6  */
7 
8 import std.stdio;
9 import std.conv;
10 import std.algorithm.searching;
11 import bindbc.sdl;
12 /**
13  * Basic Force Feedback implementation.
14  */
15 public class ForceFeedbackHandler{
16 	public SDL_Haptic*[] haptic;
17 	private InputHandler src;
18 
19 	public this(InputHandler src){
20 		SDL_InitSubSystem(SDL_INIT_HAPTIC);
21 		this.src = src;
22 		foreach(SDL_Joystick* p; src.joysticks){
23 
24 			if(p !is null){
25 				haptic ~= SDL_HapticOpenFromJoystick(p);
26 				//;
27 
28 				if(SDL_HapticRumbleSupported(haptic[haptic.length-1]) == SDL_TRUE){
29 					SDL_HapticRumbleInit(haptic[haptic.length-1]);
30 				}
31 			}
32 		}
33 	}
34 	public void reinitalize(){
35 		foreach(SDL_Joystick* p; src.joysticks){
36 			haptic.length = 0;
37 			if(p !is null){
38 				haptic ~= SDL_HapticOpenFromJoystick(p);
39 				//;
40 
41 				if(SDL_HapticRumbleSupported(haptic[haptic.length-1]) == SDL_TRUE){
42 					SDL_HapticRumbleInit(haptic[haptic.length-1]);
43 				}
44 			}
45 		}
46 	}
47 
48 	public void addEffect(int deviceID, SDL_HapticEffect* type){
49 		SDL_HapticNewEffect(haptic[deviceID], type);
50 	}
51 	public void runEffect(int deviceID, int num, uint type){
52 		SDL_HapticRunEffect(haptic[deviceID], num, type);
53 	}
54 	public void updateEffect(int deviceID, int num, SDL_HapticEffect* type){
55 		SDL_HapticUpdateEffect(haptic[deviceID], num, type);
56 	}
57 	public void stopEffect(int deviceID, int num){
58 		SDL_HapticStopEffect(haptic[deviceID], num);
59 	}
60 
61 	public void runRumbleEffect(int deviceID, float strenght, uint duration){
62 		SDL_HapticRumblePlay(haptic[deviceID], strenght, duration);
63 	}
64 	public void stopRumbleEffect(int deviceID){
65 		SDL_HapticRumbleStop(haptic[deviceID]);
66 	}
67 }
68 /**
69  * Handles the events for the various input devices.
70  */
71 public class InputHandler : TextInputHandler{
72 	public AxisListener[] al;
73 	public InputListener[] il;
74 	public MouseListener[] ml;
75 	public TextInputListener[] tl;
76 	public SystemEventListener[] sel;
77 	private TextInputListener tiSelect;
78 	private bool tiEnable, enableBindingCapture, delOldOnEvent, delConflKeys, exitOnSysKeys;
79 	//private string name;
80 	public KeyBinding[] kb;
81 	private string hatpos, proposedID;
82 	private int mouseX, mouseY;
83 	public SDL_Joystick*[] joysticks;
84 	public string[] joyNames;
85 	public int[] joyButtons, joyAxes, joyHats;
86 	///Upon construction, it detects the connected joysticks.
87 	public this(){
88 		SDL_InitSubSystem(SDL_INIT_JOYSTICK);
89 		int j = SDL_NumJoysticks();
90 		for(int i ; i < j ; i++){
91 			joysticks ~= SDL_JoystickOpen(i);
92 			if(joysticks[i] !is null){
93 				joyNames ~= to!string(SDL_JoystickName(joysticks[i]));
94 				joyButtons ~= SDL_JoystickNumButtons(joysticks[i]);
95 				joyAxes ~= SDL_JoystickNumAxes(joysticks[i]);
96 				joyHats ~= SDL_JoystickNumHats(joysticks[i]);
97 				/*writeln("Buttons: ", SDL_JoystickNumButtons(joysticks[i]));
98 				 writeln("Axes: ", SDL_JoystickNumAxes(joysticks[i]));
99 				 writeln("Hats: ", SDL_JoystickNumHats(joysticks[i]));*/
100 			}
101 		}
102 	}
103 
104 	~this(){
105 		foreach(SDL_Joystick* p; joysticks)
106 			SDL_JoystickClose(p);
107 	}
108 	/**
109 	 * Captures a key for binding
110 	 */
111 	public void captureEvent(string proposedID, bool delOldOnEvent, bool delConflKeys, bool exitOnSysKeys){
112 		this.proposedID = proposedID;
113 		enableBindingCapture = true;
114 		this.delOldOnEvent = delOldOnEvent;
115 		this.delConflKeys = delConflKeys;
116 		this.exitOnSysKeys = exitOnSysKeys;
117 	}
118 	/**
119 	 * Polls for events. If there's any, calls the eventlisteners.
120 	 */
121 	public void test(){
122 		SDL_Event event;
123 		while(SDL_PollEvent(&event)){
124 			//writeln(event.type);
125 			if(enableBindingCapture){
126 
127 				KeyBinding kb0;
128 				if(event.type == SDL_KEYDOWN){
129 					kb0 = KeyBinding(event.key.keysym.mod, event.key.keysym.scancode, 0, proposedID, Devicetype.KEYBOARD);
130 					enableBindingCapture = false;
131 				}else if(event.type == SDL_JOYBUTTONDOWN){
132 
133 					kb0 = KeyBinding(0, event.jbutton.button, event.jbutton.which, proposedID, Devicetype.JOYSTICK);
134 					enableBindingCapture = false;
135 				}else if(event.type == SDL_JOYHATMOTION){
136 					kb0 = KeyBinding(4, event.jhat.hat, event.jhat.which, proposedID, Devicetype.JOYSTICK);
137 					enableBindingCapture = false;
138 				}else if(event.type == SDL_JOYAXISMOTION){
139 
140 					if((event.jaxis.value > 4096 || event.jaxis.value <-4096)){
141 						kb0 = KeyBinding(8, event.jaxis.axis, event.jaxis.which, proposedID, Devicetype.JOYSTICK);
142 						enableBindingCapture = false;
143 					}
144 				}
145 				if(!enableBindingCapture){
146 					if(exitOnSysKeys){
147 						foreach(KeyBinding kb1; kb){
148 							if(kb1.conflKey(kb0) && kb1.ID[0..3] == "sys"){
149 								return;
150 
151 							}
152 						}
153 
154 					}
155 					int[] removelist;
156 					if(delOldOnEvent){
157 						for(int i; i < kb.length; i++){
158 							if(kb[i].ID == kb0.ID){
159 								removelist ~= i;
160 							}
161 						}
162 					}
163 					if(delConflKeys){
164 						for(int i; i < kb.length; i++){
165 							if(kb[i].conflKey(kb0)){
166 								removelist ~= i;
167 							}
168 						}
169 					}
170 
171 					if(delOldOnEvent && delConflKeys){
172 						KeyBinding[] kb1;
173 						for(int i; i < kb.length; i++){
174 							if(count(removelist, i) == 0){
175 								kb1 ~= kb[i];
176 							}
177 						}
178 						kb = kb1;
179 					}
180 					kb ~= kb0;
181 				}
182 			}
183 			switch(event.type){
184 				case SDL_KEYDOWN:
185 
186 					if(!tiEnable){
187 						foreach(k; kb){
188 							if(event.key.keysym.scancode == k.scancode && ((event.key.keysym.mod | k.keymodIgnore) == (k.keymod | k.keymodIgnore)) && k.devicetype == Devicetype.KEYBOARD){
189 								invokeKeyPressed(k.ID, event.key.timestamp, 0, Devicetype.KEYBOARD);
190 							}
191 						}
192 					}else{
193 						switch(event.key.keysym.scancode){
194 							case SDL_SCANCODE_RETURN, SDL_SCANCODE_RETURN2, SDL_SCANCODE_KP_ENTER:
195 								tiSelect.textInputKeyEvent(event.key.timestamp, event.key.windowID, TextInputKey.ENTER);
196 								break;
197 							case SDL_SCANCODE_ESCAPE:
198 								tiSelect.textInputKeyEvent(event.key.timestamp, event.key.windowID, TextInputKey.ESCAPE);
199 								break;
200 							case SDL_SCANCODE_BACKSPACE:
201 								tiSelect.textInputKeyEvent(event.key.timestamp, event.key.windowID, TextInputKey.BACKSPACE);
202 								break;
203 							case SDL_SCANCODE_UP:
204 								tiSelect.textInputKeyEvent(event.key.timestamp, event.key.windowID, TextInputKey.CURSORUP);
205 								break;
206 							case SDL_SCANCODE_DOWN:
207 								tiSelect.textInputKeyEvent(event.key.timestamp, event.key.windowID, TextInputKey.CURSORDOWN);
208 								break;
209 							case SDL_SCANCODE_LEFT:
210 								tiSelect.textInputKeyEvent(event.key.timestamp, event.key.windowID, TextInputKey.CURSORLEFT);
211 								break;
212 							case SDL_SCANCODE_RIGHT:
213 								tiSelect.textInputKeyEvent(event.key.timestamp, event.key.windowID, TextInputKey.CURSORRIGHT);
214 								break;
215 							case SDL_SCANCODE_INSERT:
216 								tiSelect.textInputKeyEvent(event.key.timestamp, event.key.windowID, TextInputKey.INSERT);
217 								break;
218 							case SDL_SCANCODE_DELETE:
219 								tiSelect.textInputKeyEvent(event.key.timestamp, event.key.windowID, TextInputKey.DELETE);
220 								break;
221 							case SDL_SCANCODE_HOME:
222 								tiSelect.textInputKeyEvent(event.key.timestamp, event.key.windowID, TextInputKey.HOME);
223 								break;
224 							case SDL_SCANCODE_END:
225 								tiSelect.textInputKeyEvent(event.key.timestamp, event.key.windowID, TextInputKey.END);
226 								break;
227 							case SDL_SCANCODE_PAGEUP:
228 								tiSelect.textInputKeyEvent(event.key.timestamp, event.key.windowID, TextInputKey.PAGEUP);
229 								break;
230 							case SDL_SCANCODE_PAGEDOWN:
231 								tiSelect.textInputKeyEvent(event.key.timestamp, event.key.windowID, TextInputKey.PAGEDOWN);
232 								break;
233 							default: break;
234 						}
235 					}
236 					break;
237 				case SDL_KEYUP:
238 					if(!tiEnable){
239 						foreach(k; kb ){
240 							if(event.key.keysym.scancode == k.scancode && ((event.key.keysym.mod | k.keymodIgnore) == (k.keymod | k.keymodIgnore)) && k.devicetype == Devicetype.KEYBOARD){
241 								invokeKeyReleased(k.ID, event.key.timestamp, 0, Devicetype.KEYBOARD);
242 							}
243 						}
244 					}
245 					break;
246 				case SDL_TEXTINPUT:
247 					if(tiEnable){
248 						import std.utf : toUTF32;
249 						tiSelect.textInputEvent(event.text.timestamp, event.text.windowID, toUTF32(event.text.text.idup));
250 					}
251 					break;
252 				case SDL_JOYBUTTONDOWN:
253 					foreach(k; kb){
254 						if(event.jbutton.button == k.scancode && 0 == k.keymod && k.devicetype == Devicetype.JOYSTICK && k.devicenumber == event.jbutton.which){
255 							invokeKeyPressed(k.ID, event.jbutton.timestamp, event.jbutton.which, Devicetype.JOYSTICK);
256 						}
257 					}
258 					break;
259 				case SDL_JOYBUTTONUP:
260 					foreach(k; kb){
261 						if(event.jbutton.button == k.scancode && 0 == k.keymod && k.devicetype == Devicetype.JOYSTICK && k.devicenumber == event.jbutton.which){
262 							invokeKeyReleased(k.ID, event.jbutton.timestamp, event.jbutton.which, Devicetype.JOYSTICK);
263 						}
264 					}
265 					break;
266 				case SDL_JOYHATMOTION:
267 					foreach(k; kb){
268 						if(event.jhat.alignof == k.scancode && 4 == k.keymod && k.devicetype == Devicetype.JOYSTICK && k.devicenumber == event.jhat.which){
269 							invokeKeyReleased(hatpos, event.jhat.timestamp, event.jhat.which, Devicetype.JOYSTICK);
270 							invokeKeyPressed(k.ID, event.jhat.timestamp, event.jhat.which, Devicetype.JOYSTICK);
271 							hatpos = k.ID;
272 						}
273 					}
274 					break;
275 				case SDL_JOYAXISMOTION:
276 					foreach(k; kb){
277 						if(event.jaxis.axis == k.scancode && 8 == k.keymod && k.devicetype == Devicetype.JOYSTICK && k.devicenumber == event.jaxis.which){
278 							invokeAxisEvent(k.ID, event.jaxis.timestamp, event.jaxis.value, event.jaxis.which, Devicetype.JOYSTICK);
279 						}
280 					}
281 					break;
282 				case SDL_MOUSEBUTTONDOWN:
283 					invokeMouseEvent(event.button.which, event.button.timestamp, event.button.windowID, event.button.button, event.button.state, event.button.clicks, event.button.x, event.button.y);
284 					break;
285 				case SDL_MOUSEBUTTONUP:
286 					invokeMouseEvent(event.button.which, event.button.timestamp, event.button.windowID, event.button.button, event.button.state, event.button.clicks, event.button.x, event.button.y);
287 					break;
288 				case SDL_MOUSEMOTION:
289 					invokeMouseMotionEvent(event.motion.timestamp, event.motion.windowID, event.motion.which, event.motion.state, event.motion.x, event.motion.y, event.motion.xrel, event.motion.yrel);
290 					mouseX = event.motion.x;
291 					mouseY = event.motion.y;
292 					break;
293 				case SDL_MOUSEWHEEL:
294 					invokeMouseWheelEvent(event.wheel.type, event.wheel.timestamp, event.wheel.windowID, event.wheel.which, event.wheel.x, event.wheel.y);
295 					break;
296 				case SDL_QUIT:
297 					invokeQuitEvent();
298 					break;
299 				case SDL_JOYDEVICEADDED:
300 					int i = event.jdevice.which;
301 					joysticks ~= SDL_JoystickOpen(i);
302 					if(joysticks[i] !is null){
303 						joyNames ~= to!string(SDL_JoystickName(joysticks[i]));
304 						joyButtons ~= SDL_JoystickNumButtons(joysticks[i]);
305 						joyAxes ~= SDL_JoystickNumAxes(joysticks[i]);
306 						joyHats ~= SDL_JoystickNumHats(joysticks[i]);
307 						/*writeln("Buttons: ", SDL_JoystickNumButtons(joysticks[i]));
308 				 writeln("Axes: ", SDL_JoystickNumAxes(joysticks[i]));
309 				 writeln("Hats: ", SDL_JoystickNumHats(joysticks[i]));*/
310 					}
311 					invokeControllerAddedEvent(i);
312 					break;
313 				case SDL_JOYDEVICEREMOVED:
314 					SDL_JoystickClose(joysticks[event.jdevice.which]);
315 					invokeControllerRemovedEvent(event.jdevice.which);
316 					break;
317 				default: break;
318 			}
319 
320 		}
321 
322 	}
323 
324 	private void invokeKeyPressed(string ID, uint timestamp, uint devicenumber, uint devicetype){
325 		foreach(i; il){
326 			if(i)
327 				i.keyPressed(ID, timestamp, devicenumber, devicetype);
328 		}
329 	}
330 	private void invokeKeyReleased(string ID, uint timestamp, uint devicenumber, uint devicetype){
331 		foreach(i; il){
332 			if(i)
333 				i.keyReleased(ID, timestamp, devicenumber, devicetype);
334 		}
335 	}
336 	private void invokeMouseEvent(uint which, uint timestamp, uint windowID, ubyte button, ubyte state, ubyte clicks, int x, int y){
337 		foreach(MouseListener m; ml){
338 			if(m)
339 				m.mouseButtonEvent(which, timestamp, windowID, button, state, clicks, x, y);
340 		}
341 	}
342 	private void invokeMouseWheelEvent(uint type, uint timestamp, uint windowID, uint which, int x, int y){
343 		foreach(MouseListener m; ml){
344 			if(m)
345 				m.mouseWheelEvent(type, timestamp, windowID, which, x, y, mouseX, mouseY);
346 		}
347 	}
348 	private void invokeMouseMotionEvent(uint timestamp, uint windowID, uint which, uint state, int x, int y, int relX, int relY){
349 		foreach(MouseListener m; ml){
350 			if(m)
351 				m.mouseMotionEvent(timestamp, windowID, which, state, x, y, relX, relY);
352 		}
353 	}
354 	private void invokeAxisEvent(string ID, uint timestamp, short val, uint devicenumber, uint devicetype){
355 		foreach(a; al){
356 			if(a)
357 				a.axisEvent(ID, timestamp, val, devicenumber, devicetype);
358 		}
359 	}
360 	private void invokeQuitEvent(){
361 		foreach(SystemEventListener q; sel){
362 			q.onQuit();
363 		}
364 	}
365 	private void invokeControllerRemovedEvent(uint ID){
366 		foreach(SystemEventListener q; sel){
367 			q.controllerRemoved(ID);
368 		}
369 	}
370 	private void invokeControllerAddedEvent(uint ID){
371 		foreach(SystemEventListener q; sel){
372 			q.controllerAdded(ID);
373 		}
374 	}
375 	///Sets wether to use the newer XInput over the older DirectInput.
376 	public static setXInput(bool state){
377 		if(state){
378 			SDL_SetHint(SDL_HINT_XINPUT_ENABLED, "1");
379 		}else{
380 			SDL_SetHint(SDL_HINT_XINPUT_ENABLED, "0");
381 		}
382 	}
383 	///Starts the TextInputEvent and disables the polling of normal input events.
384 	public void startTextInput(TextInputListener tl){
385 		if(tiSelect !is null){
386 			tiSelect.dropTextInput();
387 		}
388 		SDL_StartTextInput();
389 		tiEnable = true;
390 
391 		tiSelect = tl;
392 	}
393 	///Stops the TextInputEvent and enables the polling of normal input events.
394 	public void stopTextInput(TextInputListener tl){
395 		SDL_StopTextInput();
396 		tl.dropTextInput();
397 		tiEnable = false;
398 		tiSelect = null;
399 	}
400 	/*public void addTextInputListener(TextInputListener til){
401 		//tl[] ~= til;
402 	}
403 	public void removeTextInputListener(TextInputListener tl){
404 		//tl.remove(ID);
405 
406 	}*/
407 	/*
408 	 * Converts between SDL and PPE key modificators.
409 	 * PPE native key modificator layout:
410 	 * bit 0: Left Shift
411 	 * bit 1: Right Shift
412 	 * bit 2: Any Shift
413 	 * bit 3: Left Control
414 	 * bit 4: Right Control
415 	 * bit 5: Any Control
416 	 * bit 6: Left Alt
417 	 * bit 7: Right Alt
418 	 * bit 8: Any Alt
419 	 * bit 9: Left OSKey
420 	 * bit 10: Right OSKey
421 	 * bit 11: Any OSKey
422 	 * bit 12: NumLock
423 	 * bit 13: CapsLock
424 	 * bit 14:
425 	 */
426 }
427 
428 
429 /**
430  * Defines a keybinding.
431  */
432 public struct KeyBinding{
433 	public uint scancode;		///The code of the phisical key relative to the US English keyboard.
434 	public uint  devicenumber;	///The identificator of the device.
435 	public uint devicetype;		///The type of the device.
436 	public ushort keymod, keymodIgnore;		///Keymod sets the modifierkeys required to activate the event, keymodIgnore sets the keys that are ignored during event polling.
437 	public string ID;		///ID of the event
438 	this(ushort keymod, uint scancode, uint devicenumber, string ID, uint devicetype, ushort keymodIgnore = KeyModifier.ANY){
439 		this.keymod = keymod;
440 		this.scancode = scancode;
441 		this.devicenumber = devicenumber;
442 		this.ID = ID;
443 		this.devicetype = devicetype;
444 		this.keymodIgnore = keymodIgnore;
445 	}
446 	///Returns if there's a conflicting key.
447 	public bool conflKey(KeyBinding a){
448 		if(a.scancode == this.scancode && a.keymod == this.keymod && a.devicenumber == this.devicenumber && a.devicetype == this.devicetype){
449 			return true;
450 		}
451 		return false;
452 	}
453 	///Returns true if the two KeyBindings have the same ID
454 	public bool conflID(KeyBinding a){
455 		if(a.ID == this.ID){
456 			return true;
457 		}
458 		return false;
459 	}
460 	///Returns true it the two KeyBindings are equal.
461 	public bool opEquals(const KeyBinding s){
462 		if(s.scancode == this.scancode && s.keymod == this.keymod && s.devicenumber == this.devicenumber && s.devicetype == this.devicetype && s.ID == this.ID){
463 			return true;
464 		}
465 		return false;
466 	}
467 	///Returns a standard string representation of the keybinding.
468 	public string toString(){
469 		string s;
470 		s ~= "ID: ";
471 		s ~= ID;
472 		s ~= " Keycode: ";
473 		s ~= to!string(scancode);
474 		s ~= " Keymod: ";
475 		s ~= to!string(keymod);
476 		s ~= " Devicetype: ";
477 		s ~= to!string(devicetype);
478 		s ~= " Devicenumber: ";
479 		s ~= to!string(devicenumber);
480 		return s;
481 	}
482 }
483 
484 public interface InputListener{
485 	public void keyPressed(string ID, uint timestamp, uint devicenumber, uint devicetype);
486 	public void keyReleased(string ID, uint timestamp, uint devicenumber, uint devicetype);
487 }
488 
489 public interface AxisListener{
490 	public void axisEvent(string ID, uint timestamp, short val, uint devicenumber, uint devicetype);
491 }
492 
493 public interface MovementListener{
494 	public void movementEvent(string ID, short x, short y, short relX, short relY, uint devicenumber, uint devicetype);
495 }
496 
497 public interface MouseListener{
498 	public void mouseButtonEvent(uint which, uint timestamp, uint windowID, ubyte button, ubyte state, ubyte clicks, int x, int y);
499 	public void mouseWheelEvent(uint type, uint timestamp, uint windowID, uint which, int x, int y, int wX, int wY);
500 	public void mouseMotionEvent(uint timestamp, uint windowID, uint which, uint state, int x, int y, int relX, int relY);
501 }
502 
503 public interface TextInputListener{
504 	public void textInputEvent(uint timestamp, uint windowID, dstring text);
505 	public void textInputKeyEvent(uint timestamp, uint windowID, TextInputKey key, ushort modifier = 0);
506 	//public void textSelectionEvent(uint timestamp, uint window, int action);
507 	//public void textClipboardEvent(uint timestamp, uint window, wstring text);
508 	public void dropTextInput();
509 }
510 
511 public interface TextInputHandler{
512 	public void startTextInput(TextInputListener tl);
513 	public void stopTextInput(TextInputListener tl);
514 	//public void addTextInputListener(TextInputListener tl); DEPRECATED!
515 	//public void removeTextInputListener(TextInputListener tl); DEPRECATED!
516 }
517 
518 public interface SystemEventListener{
519 	public void onQuit();
520 	public void controllerRemoved(uint ID);
521 	public void controllerAdded(uint ID);
522 }
523 
524 public enum Devicetype{
525 	KEYBOARD	= 0,
526 	JOYSTICK	= 1,
527 	MOUSE		= 2,
528 	TOUCHSCREEN	= 3
529 }
530 
531 public enum TextInputKey{
532 	ENTER		= 1,
533 	ESCAPE		= 2,
534 	BACKSPACE	= 3,
535 	CURSORUP	= 4,
536 	CURSORDOWN	= 5,
537 	CURSORLEFT	= 6,
538 	CURSORRIGHT	= 7,
539 	INSERT		= 8,
540 	DELETE		= 9,
541 	HOME		= 10,
542 	END			= 11,
543 	PAGEUP		= 12,
544 	PAGEDOWN	= 13
545 }
546 
547 public enum TextInputType : uint{
548 	NULL		= 0,
549 	TEXT		= 1,
550 	DECIMAL		= 2,
551 	DISABLE		= 65536, ///For use in listboxes
552 }
553 
554 /// Standard key modifiers to avoid public SDL imports and to allow alternative library backends.
555 public enum KeyModifier : ushort{
556 	NONE 		= 0x0000,
557 	LSHIFT 		= 0x0001,
558 	RSHIFT 		= 0x0002,
559 	SHIFT 		= 0x0003,
560 	LCTRL 		= 0x0040,
561 	RCTRL	 	= 0x0080,
562 	CTRL 		= 0x00C0,
563 	LALT 		= 0x0100,
564 	RALT 		= 0x0200,
565 	ALT 		= 0x0300,
566 	LGUI 		= 0x0400,
567 	RGUI	 	= 0x0800,
568 	GUI 		= 0x0C00,
569 	NUM 		= 0x1000,
570 	CAPS 		= 0x2000,
571 	LOCKKEYIGNORE	= NUM + CAPS,		///Use this if only Caps lock and Num lock needs to be ignored
572 	MODE 		= 0x4000,
573 	RESERVED 	= 0x8000,
574 	ANY			= 0xFFFF
575 }
576 public enum JoyModifier : ushort{
577 	BUTTONS		= 0x0000,
578 	DPAD		= 0x0004,
579 	AXIS		= 0x0008
580 }
581 public enum MouseButton : ubyte{
582 	LEFT		= 1,
583 	MID			= 2,
584 	RIGHT		= 3,
585 	NEXT		= 4,
586 	PREVIOUS	= 5
587 }
588 public enum ButtonState : ubyte{
589 	RELEASED	= 0,
590 	PRESSED		= 1
591 }
592 public enum ScanCode : uint{
593 	A				=	4,
594 	B				=	5,
595 	C				=	6,
596 	D				=	7,
597 	E				=	8,
598 	F				=	9,
599 	G				=	10,
600 	H				=	11,
601 	I				=	12,
602 	J				=	13,
603 	K				=	14,
604 	L				=	15,
605 	M				=	16,
606 	N				=	17,
607 	O				=	18,
608 	P				=	19,
609 	Q				=	20,
610 	R				=	21,
611 	S				=	22,
612 	T				=	23,
613 	U				=	24,
614 	V				=	25,
615 	W				=	26,
616 	X				=	27,
617 	Y				=	28,
618 	Z				=	29,
619 
620 	n1				=	30,
621 	n2				=	31,
622 	n3				=	32,
623 	n4				=	33,
624 	n5				=	34,
625 	n6				=	35,
626 	n7				=	36,
627 	n8				=	37,
628 	n9				=	38,
629 	n0				=	39,
630 
631 	ENTER			=	40,
632 	ESCAPE			=	41,
633 	BACKSPACE		=	42,
634 	TAB				=	43,
635 	SPACE			=	44,
636 
637 	MINUS			=	45,
638 	EQUALS			=	46,
639 	LEFTBRACKET		=	47,
640 	RIGHTBRACKET	=	48,
641 	BACKSLASH		=	49,
642 	NONUSLASH		=	50,
643 	SEMICOLON		=	51,
644 	APOSTROPHE		=	52,
645 	GRAVE			=	53,
646 	COMMA			=	54,
647 	PERIOD			=	55,
648 	SLASH			=	56,
649 	CAPSLOCK		=	57,
650 
651 	F1				=	58,
652 	F2				=	59,
653 	F3				=	60,
654 	F4				=	61,
655 	F5				=	62,
656 	F6				=	63,
657 	F7				=	64,
658 	F8				=	65,
659 	F9				=	66,
660 	F10				=	67,
661 	F11				=	68,
662 	F12				=	69,
663 
664 	PRINTSCREEN		=	70,
665 	SCROLLLOCK		=	71,
666 	PAUSE			=	72,
667 	INSERT			=	73,
668 	HOME			=	74,
669 	PAGEUP			=	75,
670 	DELETE			=	76,
671 	END				=	77,
672 	PAGEDOWN		=	78,
673 	RIGHT			=	79,
674 	LEFT			=	80,
675 	DOWN			=	81,
676 	UP				=	82,
677 
678 	NUMLOCK			=	83,
679 	NP_DIVIDE		=	84,
680 	NP_MULTIPLY		=	85,
681 	NP_MINUS		=	86,
682 	NP_PLUS			=	87,
683 	NP_ENTER		=	88,
684 
685 	np1				=	89,
686 	np2				=	90,
687 	np3				=	91,
688 	np4				=	92,
689 	np5				=	93,
690 	np6				=	94,
691 	np7				=	95,
692 	np8				=	96,
693 	np9				=	97,
694 	np0				=	98,
695 
696 	NP_PERIOD		=	99,
697 
698 	NONUSBACKSLASH	=	100,
699 	APPLICATION		=	101,
700 
701 	NP_EQUALS		=	102,
702 
703 	F13				=	104,
704 	F14				=	105,
705 	F15				=	106,
706 	F16				=	107,
707 	F17				=	108,
708 	F18				=	109,
709 	F19				=	110,
710 	F20				=	111,
711 	F21				=	112,
712 	F22				=	113,
713 	F23				=	114,
714 	F24				=	115,
715 
716 	EXECUTE			=	116,
717 	HELP			=	117,
718 	MENU			=	118,
719 	SELECT			=	119,
720 	STOP			=	120,
721 	REDO			=	121,
722 	UNDO			=	122,
723 	CUT				=	123,
724 	COPY			=	124,
725 	PASTE			=	125,
726 	FIND			=	126,
727 	MUTE			=	127,
728 	VOLUME_UP		=	128,
729 	VOLUME_DOWN		=	129,
730 
731 	NP_COMMA		=	133,
732 	NP_EQUALSAS400	=	134,
733 
734 	INTERNATIONAL1	=	135,
735 	INTERNATIONAL2	=	136,
736 	INTERNATIONAL3	=	137,
737 	INTERNATIONAL4	=	138,
738 	INTERNATIONAL5	=	139,
739 	INTERNATIONAL6	=	140,
740 	INTERNATIONAL7	=	141,
741 	INTERNATIONAL8	=	142,
742 	INTERNATIONAL9	=	143,
743 
744 	LANGUAGE1		=	144,
745 	LANGUAGE2		=	145,
746 	LANGUAGE3		=	146,
747 	LANGUAGE4		=	147,
748 	LANGUAGE5		=	148,
749 	LANGUAGE6		=	149,
750 	LANGUAGE7		=	150,
751 	LANGUAGE8		=	151,
752 	LANGUAGE9		=	152,
753 
754 	ALTERASE		=	153,
755 	SYSREQ			=	154,
756 	CANCEL			=	155,
757 	PRIOR			=	157,
758 	ENTER2			=	158,
759 	SEPARATOR		=	159,
760 	OUT				=	160,
761 	OPERATE			=	161,
762 	CLEARAGAIN		=	162,
763 	CRSEL			=	163,
764 	EXSEL			=	164,
765 
766 	NP00			=	176,
767 	NP000			=	177,
768 	THROUSANDSEPAR	=	178,
769 	HUNDREDSSEPAR	=	179,
770 	CURRENCYUNIT	=	180,
771 	CURRENCYSUBUNIT	=	181,
772 	NP_LEFTPAREN	=	182,
773 	NP_RIGHTPAREN	=	183,
774 	NP_LEFTBRACE	=	184,
775 	NP_RIGHTBRACE	=	185,
776 	NP_TAB			=	186,
777 	NP_BACKSPACE	=	187,
778 	NP_A			=	188,
779 	NP_B			=	189,
780 	NP_C			=	190,
781 	NP_D			=	191,
782 	NP_E			=	192,
783 	NP_F			=	193,
784 	NP_XOR			=	194,
785 	NP_POWER		=	195,
786 	NP_PERCENT		=	196,
787 	NP_LESS			=	197,
788 	NP_GREATER		=	198,
789 	NP_AMPERSAND	=	199,
790 	NP_DBAMPERSAND	=	200,
791 	NP_VERTICALBAR	=	201,
792 	NP_DBVERTICALBAR=	202,
793 	NP_COLON		=	203,
794 	NP_HASH			=	204,
795 	NP_SPACE		=	205,
796 	NP_AT			=	206,
797 	NP_EXCLAM		=	207,
798 	NP_MEMSTORE		=	208,
799 	NP_MEMRECALL	=	209,
800 	NP_MEMCLEAR		=	210,
801 	NP_MEMADD		=	211,
802 	NP_MEMSUBSTRACT	=	212,
803 	NP_MEMMULTIPLY	=	213,
804 	NP_MEMDIVIDE	=	214,
805 	NP_PLUSMINUS	=	215,
806 	NP_CLEAR		=	216,
807 	NP_CLEARENTRY	=	217,
808 	NP_BINARY		=	218,
809 	NP_OCTAL		=	219,
810 	NP_DECIMAL		=	220,
811 	NP_HEXADECIMAL	=	221,
812 
813 	LCTRL			=	224,
814 	LSHIFT			=	225,
815 	LALT			=	226,
816 	LGUI			=	227,
817 	RCTRL			=	228,
818 	RSHIFT			=	229,
819 	RALT			=	230,
820 	RGUI			=	231,
821 
822 	AUDIONEXT		=	258,
823 	AUDIOPREV		=	259,
824 	AUDIOSTOP		=	260,
825 	AUDIOPLAY		=	261,
826 	AUDIOMUTE		=	262,
827 	MEDIASELECT		=	263,
828 	WWW				=	264,
829 	MAIL			=	265,
830 	CALCULATOR		=	266,
831 	COMPUTER		=	267,
832 }