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