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 public class ForceFeedbackHandler{
14 	public SDL_Haptic*[] haptic;
15 	private InputHandler src;
16 
17 	public this(InputHandler src){
18 		SDL_InitSubSystem(SDL_INIT_HAPTIC);
19 		this.src = src;
20 		foreach(SDL_Joystick* p; src.joysticks){
21 
22 			if(p !is null){
23 				haptic ~= SDL_HapticOpenFromJoystick(p);
24 				//;
25 
26 				if(SDL_HapticRumbleSupported(haptic[haptic.length-1]) == SDL_TRUE){
27 					SDL_HapticRumbleInit(haptic[haptic.length-1]);
28 				}
29 			}
30 		}
31 	}
32 	public void reinitalize(){
33 		foreach(SDL_Joystick* p; src.joysticks){
34 			haptic.length = 0;
35 			if(p !is null){
36 				haptic ~= SDL_HapticOpenFromJoystick(p);
37 				//;
38 				
39 				if(SDL_HapticRumbleSupported(haptic[haptic.length-1]) == SDL_TRUE){
40 					SDL_HapticRumbleInit(haptic[haptic.length-1]);
41 				}
42 			}
43 		}
44 	}
45 
46 	public void addEffect(int deviceID, SDL_HapticEffect* type){
47 		SDL_HapticNewEffect(haptic[deviceID], type);
48 	}
49 	public void runEffect(int deviceID, int num, uint type){
50 		SDL_HapticRunEffect(haptic[deviceID], num, type);
51 	}
52 	public void updateEffect(int deviceID, int num, SDL_HapticEffect* type){
53 		SDL_HapticUpdateEffect(haptic[deviceID], num, type);
54 	}
55 	public void stopEffect(int deviceID, int num){
56 		SDL_HapticStopEffect(haptic[deviceID], num);
57 	}
58 
59 	public void runRumbleEffect(int deviceID, float strenght, uint duration){
60 		SDL_HapticRumblePlay(haptic[deviceID], strenght, duration);
61 	}
62 	public void stopRumbleEffect(int deviceID){
63 		SDL_HapticRumbleStop(haptic[deviceID]);
64 	}
65 }
66 
67 public class InputHandler : TextInputHandler{
68 	public AxisListener[] al;
69 	public InputListener[] il;
70 	public MouseListener[] ml;
71 	public TextInputListener[string] tl;
72 	public SystemEventListener[] sel;
73 	private string tiSelect;
74 	private bool tiEnable, enableBindingCapture, delOldOnEvent, delConflKeys, exitOnSysKeys;
75 	//private string name;
76 	public KeyBinding[] kb;
77 	private string hatpos, proposedID;
78 	private int mouseX, mouseY;
79 	public SDL_Joystick*[] joysticks;
80 	public string[] joyNames;
81 	public int[] joyButtons, joyAxes, joyHats;
82 	
83 	public this(){
84 		SDL_InitSubSystem(SDL_INIT_JOYSTICK);
85 		int j = SDL_NumJoysticks();
86 		for(int i ; i < j ; i++){
87 			joysticks ~= SDL_JoystickOpen(i);
88 			if(joysticks[i] !is null){
89 				joyNames ~= to!string(SDL_JoystickName(joysticks[i]));
90 				joyButtons ~= SDL_JoystickNumButtons(joysticks[i]);
91 				joyAxes ~= SDL_JoystickNumAxes(joysticks[i]);
92 				joyHats ~= SDL_JoystickNumHats(joysticks[i]);
93 				/*writeln("Buttons: ", SDL_JoystickNumButtons(joysticks[i]));
94 				 writeln("Axes: ", SDL_JoystickNumAxes(joysticks[i]));
95 				 writeln("Hats: ", SDL_JoystickNumHats(joysticks[i]));*/
96 			}
97 		}
98 	}
99 	
100 	/*~this(){
101 	 foreach(SDL_Joystick* p; joysticks)
102 	 SDL_JoystickClose(p);
103 	 }*/
104 	/*
105 	 * Captures a key for binding
106 	 */
107 	public void captureEvent(string proposedID, bool delOldOnEvent, bool delConflKeys, bool exitOnSysKeys){
108 		this.proposedID = proposedID;
109 		enableBindingCapture = true;
110 		this.delOldOnEvent = delOldOnEvent;
111 		this.delConflKeys = delConflKeys;
112 		this.exitOnSysKeys = exitOnSysKeys;
113 	}
114 	
115 	public void test(){
116 		SDL_Event event;
117 		while(SDL_PollEvent(&event)){
118 			//writeln(event.type);
119 			if(enableBindingCapture){
120 				
121 				KeyBinding kb0;
122 				if(event.type == SDL_KEYDOWN){
123 					kb0 = KeyBinding(event.key.keysym.mod, event.key.keysym.scancode, 0, proposedID, Devicetype.KEYBOARD);
124 					enableBindingCapture = false;
125 				}else if(event.type == SDL_JOYBUTTONDOWN){
126 					
127 					kb0 = KeyBinding(0, event.jbutton.button, event.jbutton.which, proposedID, Devicetype.JOYSTICK);
128 					enableBindingCapture = false;
129 				}else if(event.type == SDL_JOYHATMOTION){
130 					kb0 = KeyBinding(4, event.jhat.hat, event.jhat.which, proposedID, Devicetype.JOYSTICK);
131 					enableBindingCapture = false;
132 				}else if(event.type == SDL_JOYAXISMOTION){
133 
134 					if((event.jaxis.value > 4096 || event.jaxis.value <-4096)){
135 						kb0 = KeyBinding(8, event.jaxis.axis, event.jaxis.which, proposedID, Devicetype.JOYSTICK);
136 						enableBindingCapture = false;
137 					}
138 				}
139 				if(!enableBindingCapture){
140 					if(exitOnSysKeys){
141 						foreach(KeyBinding kb1; kb){
142 							if(kb1.conflKey(kb0) && kb1.ID[0] == 's' && kb1.ID[1] == 'y' && kb1.ID[2] == 's'){
143 								return;
144 
145 							}
146 						}
147 
148 					}
149 					int[] removelist;
150 					if(delOldOnEvent){
151 						for(int i; i < kb.length; i++){
152 							if(kb[i].ID == kb0.ID){
153 								removelist ~= i;
154 							}
155 						}
156 					}
157 					if(delConflKeys){
158 						for(int i; i < kb.length; i++){
159 							if(kb[i].conflKey(kb0)){
160 								removelist ~= i;
161 							}
162 						}
163 					}
164 					
165 					if(delOldOnEvent && delConflKeys){
166 						KeyBinding[] kb1;
167 						for(int i; i < kb.length; i++){
168 							if(count(removelist, i) == 0){
169 								kb1 ~= kb[i];
170 							}
171 						}
172 						kb = kb1;
173 					}
174 					kb ~= kb0;
175 				}
176 			}
177 
178 
179 			switch(event.type){
180 				case SDL_KEYDOWN:
181 
182 					if(!tiEnable){
183 						foreach(k; kb){
184 							if(event.key.keysym.scancode == k.keycode && event.key.keysym.mod == k.keymod && k.devicetype == Devicetype.KEYBOARD){
185 
186 								invokeKeyPressed(k.ID, event.key.timestamp, 0, Devicetype.KEYBOARD);
187 							}
188 						}
189 					}
190 					else{
191 						switch(event.key.keysym.scancode){
192 							case SDL_SCANCODE_RETURN: tl[tiSelect].textInputKeyEvent(event.key.timestamp, event.key.windowID, InputKey.ENTER); break;
193 							case SDL_SCANCODE_ESCAPE: tl[tiSelect].textInputKeyEvent(event.key.timestamp, event.key.windowID, InputKey.ESCAPE); break;
194 							case SDL_SCANCODE_BACKSPACE: tl[tiSelect].textInputKeyEvent(event.key.timestamp, event.key.windowID, InputKey.BACKSPACE); break;
195 							case SDL_SCANCODE_UP: tl[tiSelect].textInputKeyEvent(event.key.timestamp, event.key.windowID, InputKey.CURSORUP); break;
196 							case SDL_SCANCODE_DOWN: tl[tiSelect].textInputKeyEvent(event.key.timestamp, event.key.windowID, InputKey.CURSORDOWN); break;
197 							case SDL_SCANCODE_LEFT: tl[tiSelect].textInputKeyEvent(event.key.timestamp, event.key.windowID, InputKey.CURSORLEFT); break;
198 							case SDL_SCANCODE_RIGHT: tl[tiSelect].textInputKeyEvent(event.key.timestamp, event.key.windowID, InputKey.CURSORRIGHT); break;
199 							case SDL_SCANCODE_INSERT: tl[tiSelect].textInputKeyEvent(event.key.timestamp, event.key.windowID, InputKey.INSERT); break;
200 							case SDL_SCANCODE_DELETE: tl[tiSelect].textInputKeyEvent(event.key.timestamp, event.key.windowID, InputKey.DELETE); break;
201 							case SDL_SCANCODE_HOME: tl[tiSelect].textInputKeyEvent(event.key.timestamp, event.key.windowID, InputKey.HOME); break;
202 							case SDL_SCANCODE_END: tl[tiSelect].textInputKeyEvent(event.key.timestamp, event.key.windowID, InputKey.END); break;
203 							case SDL_SCANCODE_PAGEUP: tl[tiSelect].textInputKeyEvent(event.key.timestamp, event.key.windowID, InputKey.PAGEUP); break;
204 							case SDL_SCANCODE_PAGEDOWN: tl[tiSelect].textInputKeyEvent(event.key.timestamp, event.key.windowID, InputKey.PAGEDOWN); break;
205 							default: break;
206 						}
207 					}
208 					break;
209 				case SDL_KEYUP:
210 					if(!tiEnable){
211 						foreach(k; kb ){
212 							if(event.key.keysym.scancode == k.keycode && event.key.keysym.mod == k.keymod && k.devicetype == Devicetype.KEYBOARD){
213 								invokeKeyReleased(k.ID, event.key.timestamp, 0, Devicetype.KEYBOARD);
214 							}
215 						}
216 					}
217 					break;
218 				case SDL_TEXTINPUT:	 
219 					if(tiEnable){
220 						tl[tiSelect].textInputEvent(event.text.timestamp, event.text.windowID, event.text.text);
221 					}
222 					break;
223 				case SDL_JOYBUTTONDOWN:
224 					foreach(k; kb){
225 						if(event.jbutton.button == k.keycode && 0 == k.keymod && k.devicetype == Devicetype.JOYSTICK && k.devicenumber == event.jbutton.which){
226 							invokeKeyPressed(k.ID, event.jbutton.timestamp, event.jbutton.which, Devicetype.JOYSTICK);
227 						}
228 					}
229 					break;
230 				case SDL_JOYBUTTONUP:
231 					foreach(k; kb){
232 						if(event.jbutton.button == k.keycode && 0 == k.keymod && k.devicetype == Devicetype.JOYSTICK && k.devicenumber == event.jbutton.which){
233 							invokeKeyReleased(k.ID, event.jbutton.timestamp, event.jbutton.which, Devicetype.JOYSTICK);
234 						}
235 					}
236 					break;
237 				case SDL_JOYHATMOTION:
238 					foreach(k; kb){
239 						if(event.jhat.alignof == k.keycode && 4 == k.keymod && k.devicetype == Devicetype.JOYSTICK && k.devicenumber == event.jhat.which){
240 							invokeKeyReleased(hatpos, event.jhat.timestamp, event.jhat.which, Devicetype.JOYSTICK);
241 							invokeKeyPressed(k.ID, event.jhat.timestamp, event.jhat.which, Devicetype.JOYSTICK);
242 							hatpos = k.ID;
243 						}
244 					}
245 					break;
246 				case SDL_JOYAXISMOTION:
247 					foreach(k; kb){
248 						if(event.jaxis.axis == k.keycode && 8 == k.keymod && k.devicetype == Devicetype.JOYSTICK && k.devicenumber == event.jaxis.which){
249 							invokeAxisEvent(k.ID, event.jaxis.timestamp, event.jaxis.value, event.jaxis.which, Devicetype.JOYSTICK);
250 						}
251 					}
252 					break;
253 				case SDL_MOUSEBUTTONDOWN: 
254 					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);
255 					break;
256 				case SDL_MOUSEBUTTONUP:
257 					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);
258 					break;
259 				case SDL_MOUSEMOTION:
260 					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);
261 					mouseX = event.motion.x;
262 					mouseY = event.motion.y;
263 					break;
264 				case SDL_MOUSEWHEEL:
265 					invokeMouseWheelEvent(event.wheel.type, event.wheel.timestamp, event.wheel.windowID, event.wheel.which, event.wheel.x, event.wheel.y);
266 					break;
267 				case SDL_QUIT:
268 					invokeQuitEvent();
269 					break;
270 				case SDL_JOYDEVICEADDED:
271 					int i = event.jdevice.which;
272 					joysticks ~= SDL_JoystickOpen(i);
273 					if(joysticks[i] !is null){
274 						joyNames ~= to!string(SDL_JoystickName(joysticks[i]));
275 						joyButtons ~= SDL_JoystickNumButtons(joysticks[i]);
276 						joyAxes ~= SDL_JoystickNumAxes(joysticks[i]);
277 						joyHats ~= SDL_JoystickNumHats(joysticks[i]);
278 						/*writeln("Buttons: ", SDL_JoystickNumButtons(joysticks[i]));
279 				 writeln("Axes: ", SDL_JoystickNumAxes(joysticks[i]));
280 				 writeln("Hats: ", SDL_JoystickNumHats(joysticks[i]));*/
281 					}
282 					invokeControllerAddedEvent(i);
283 					break;
284 				case SDL_JOYDEVICEREMOVED:
285 					SDL_JoystickClose(joysticks[event.jdevice.which]);
286 					invokeControllerRemovedEvent(event.jdevice.which);
287 					break;
288 				default: break;
289 
290 			}
291 
292 
293 			/*if(event.type == SDL_KEYDOWN){
294 				if(!tiEnable){
295 					foreach(k; kb){
296 						if(event.key.keysym.scancode == k.keycode && event.key.keysym.mod == k.keymod && k.devicetype == Devicetype.KEYBOARD){
297 							invokeKeyPressed(k.ID, event.key.timestamp, 0, Devicetype.KEYBOARD);
298 						}
299 					}
300 				}
301 				else{
302 					switch(event.key.keysym.scancode){
303 						case SDL_SCANCODE_RETURN: tl[tiSelect].textInputKeyEvent(event.key.timestamp, event.key.windowID, InputKey.ENTER); break;
304 						case SDL_SCANCODE_ESCAPE: tl[tiSelect].textInputKeyEvent(event.key.timestamp, event.key.windowID, InputKey.ESCAPE); break;
305 						case SDL_SCANCODE_BACKSPACE: tl[tiSelect].textInputKeyEvent(event.key.timestamp, event.key.windowID, InputKey.BACKSPACE); break;
306 						case SDL_SCANCODE_UP: tl[tiSelect].textInputKeyEvent(event.key.timestamp, event.key.windowID, InputKey.CURSORUP); break;
307 						case SDL_SCANCODE_DOWN: tl[tiSelect].textInputKeyEvent(event.key.timestamp, event.key.windowID, InputKey.CURSORDOWN); break;
308 						case SDL_SCANCODE_LEFT: tl[tiSelect].textInputKeyEvent(event.key.timestamp, event.key.windowID, InputKey.CURSORLEFT); break;
309 						case SDL_SCANCODE_RIGHT: tl[tiSelect].textInputKeyEvent(event.key.timestamp, event.key.windowID, InputKey.CURSORRIGHT); break;
310 						case SDL_SCANCODE_INSERT: tl[tiSelect].textInputKeyEvent(event.key.timestamp, event.key.windowID, InputKey.INSERT); break;
311 						case SDL_SCANCODE_DELETE: tl[tiSelect].textInputKeyEvent(event.key.timestamp, event.key.windowID, InputKey.DELETE); break;
312 						case SDL_SCANCODE_HOME: tl[tiSelect].textInputKeyEvent(event.key.timestamp, event.key.windowID, InputKey.HOME); break;
313 						case SDL_SCANCODE_END: tl[tiSelect].textInputKeyEvent(event.key.timestamp, event.key.windowID, InputKey.END); break;
314 						case SDL_SCANCODE_PAGEUP: tl[tiSelect].textInputKeyEvent(event.key.timestamp, event.key.windowID, InputKey.PAGEUP); break;
315 						case SDL_SCANCODE_PAGEDOWN: tl[tiSelect].textInputKeyEvent(event.key.timestamp, event.key.windowID, InputKey.PAGEDOWN); break;
316 						default: break;
317 					}
318 				}
319 			}
320 			else if(event.type == SDL_KEYUP && !tiEnable){
321 				foreach(k; kb ){
322 					if(event.key.keysym.scancode == k.keycode && event.key.keysym.mod == k.keymod && k.devicetype == Devicetype.KEYBOARD){
323 						invokeKeyReleased(k.ID, event.key.timestamp, 0, Devicetype.KEYBOARD);
324 					}
325 				}
326 			}
327 			else if(event.type == SDL_TEXTINPUT && tiEnable){
328 				
329 				tl[tiSelect].textInputEvent(event.text.timestamp, event.text.windowID, event.text.text);
330 			}
331 			else if(event.type == SDL_JOYBUTTONDOWN){
332 				//writeln(event.jbutton.button);
333 				foreach(k; kb){
334 					if(event.jbutton.button == k.keycode && 0 == k.keymod && k.devicetype == Devicetype.JOYSTICK && k.devicenumber == event.jbutton.which){
335 						invokeKeyPressed(k.ID, event.jbutton.timestamp, event.jbutton.which, Devicetype.JOYSTICK);
336 					}
337 				}
338 			}
339 			else if(event.type == SDL_JOYBUTTONUP){
340 				foreach(k; kb){
341 					if(event.jbutton.button == k.keycode && 0 == k.keymod && k.devicetype == Devicetype.JOYSTICK && k.devicenumber == event.jbutton.which){
342 						invokeKeyReleased(k.ID, event.jbutton.timestamp, event.jbutton.which, Devicetype.JOYSTICK);
343 					}
344 				}
345 			}
346 			else if(event.type == SDL_JOYHATMOTION){
347 				foreach(k; kb){
348 					if(event.jhat.alignof == k.keycode && 4 == k.keymod && k.devicetype == Devicetype.JOYSTICK && k.devicenumber == event.jhat.which){
349 						invokeKeyReleased(hatpos, event.jhat.timestamp, event.jhat.which, Devicetype.JOYSTICK);
350 						invokeKeyPressed(k.ID, event.jhat.timestamp, event.jhat.which, Devicetype.JOYSTICK);
351 						hatpos = k.ID;
352 					}
353 				}
354 			}
355 			else if(event.type == SDL_JOYAXISMOTION){
356 				//writeln(event.jaxis.axis,',',event.jaxis.value);
357 				foreach(k; kb){
358 					if(event.jaxis.axis == k.keycode && 8 == k.keymod && k.devicetype == Devicetype.JOYSTICK && k.devicenumber == event.jaxis.which){
359 						invokeAxisEvent(k.ID, event.jaxis.timestamp, event.jaxis.value, event.jaxis.which, Devicetype.JOYSTICK);
360 					}
361 				}
362 			}
363 			else if(event.type == SDL_MOUSEBUTTONDOWN || event.type == SDL_MOUSEBUTTONUP){
364 				
365 				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);
366 				
367 			}
368 			else if(event.type == SDL_MOUSEMOTION){
369 				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);
370 				mouseX = event.motion.x;
371 				mouseY = event.motion.y;
372 			}
373 			else if(event.type == SDL_MOUSEWHEEL){
374 				invokeMouseWheelEvent(event.wheel.type, event.wheel.timestamp, event.wheel.windowID, event.wheel.which, event.wheel.x, event.wheel.y);
375 			}
376 			else if(event.type == SDL_QUIT){
377 				invokeQuitEvent();
378 			}
379 			else if(event.type == SDL_JOYDEVICEADDED){
380 				int i = event.jdevice.which;
381 				joysticks ~= SDL_JoystickOpen(i);
382 				if(joysticks[i] !is null){
383 					joyNames ~= to!string(SDL_JoystickName(joysticks[i]));
384 					joyButtons ~= SDL_JoystickNumButtons(joysticks[i]);
385 					joyAxes ~= SDL_JoystickNumAxes(joysticks[i]);
386 					joyHats ~= SDL_JoystickNumHats(joysticks[i]);
387 
388 				}
389 				invokeControllerAddedEvent(i);
390 			}
391 			else if(event.type == SDL_JOYDEVICEREMOVED){
392 				SDL_JoystickClose(joysticks[event.jdevice.which]);
393 				invokeControllerRemovedEvent(event.jdevice.which);
394 			}*/
395 		}
396 
397 	}
398 	
399 	private void invokeKeyPressed(string ID, Uint32 timestamp, Uint32 devicenumber, Uint32 devicetype){
400 		foreach(i; il){
401 			i.keyPressed(ID, timestamp, devicenumber, devicetype);
402 		}
403 	}
404 	private void invokeKeyReleased(string ID, Uint32 timestamp, Uint32 devicenumber, Uint32 devicetype){
405 		foreach(i; il){
406 			i.keyReleased(ID, timestamp, devicenumber, devicetype);
407 		}
408 	}
409 	private void invokeMouseEvent(Uint32 which, Uint32 timestamp, Uint32 windowID, Uint8 button, Uint8 state, Uint8 clicks, Sint32 x, Sint32 y){
410 		foreach(MouseListener m; ml){
411 			
412 			m.mouseButtonEvent(which, timestamp, windowID, button, state, clicks, x, y);
413 		}
414 	}
415 	private void invokeMouseWheelEvent(Uint32 type, Uint32 timestamp, Uint32 windowID, Uint32 which, Sint32 x, Sint32 y){
416 		foreach(MouseListener m; ml){
417 			
418 			m.mouseWheelEvent(type, timestamp, windowID, which, x, y, mouseX, mouseY);
419 		}
420 	}
421 	private void invokeMouseMotionEvent(uint timestamp, uint windowID, uint which, uint state, int x, int y, int relX, int relY){
422 		foreach(MouseListener m; ml){
423 			
424 			m.mouseMotionEvent(timestamp, windowID, which, state, x, y, relX, relY);
425 		}
426 	}
427 	private void invokeAxisEvent(string ID, Uint32 timestamp, Sint16 val, Uint32 devicenumber, Uint32 devicetype){
428 		foreach(a; al){
429 			a.axisEvent(ID, timestamp, val, devicenumber, devicetype);
430 		}
431 	}
432 	private void invokeQuitEvent(){
433 		foreach(SystemEventListener q; sel){
434 			q.onQuit();
435 		}
436 	}
437 	private void invokeControllerRemovedEvent(uint ID){
438 		foreach(SystemEventListener q; sel){
439 			q.controllerRemoved(ID);
440 		}
441 	}
442 	private void invokeControllerAddedEvent(uint ID){
443 		foreach(SystemEventListener q; sel){
444 			q.controllerAdded(ID);
445 		}
446 	}
447 	public static setXInput(bool state){
448 		if(state){
449 			SDL_SetHint(SDL_HINT_XINPUT_ENABLED, "1");
450 		}else{
451 			SDL_SetHint(SDL_HINT_XINPUT_ENABLED, "0");
452 		}
453 	}
454 	public void startTextInput(string ID){
455 		if(tiSelect !is null){
456 			if(tl.get(tiSelect, null) !is null)
457 				tl[tiSelect].dropTextInput();
458 			else
459 				tl.remove(tiSelect);
460 
461 		}
462 		SDL_StartTextInput();
463 		tiEnable = true;
464 
465 		tiSelect = ID;
466 	}
467 	public void stopTextInput(string ID){
468 		SDL_StopTextInput();
469 		tiEnable = false;
470 		tiSelect = null;
471 	}
472 	public void addTextInputListener(string ID, TextInputListener til){
473 		tl[ID] = til;
474 	}
475 }
476 
477 
478 
479 public struct KeyBinding{
480 	public Uint32 keycode, devicenumber, devicetype;
481 	public Uint16 keymod;
482 	public string ID;
483 	
484 	//public string device;
485 	
486 	this(ushort keymod, uint keycode, uint devicenumber, string ID, uint devicetype){
487 		this.keymod = keymod;
488 		this.keycode = keycode;
489 		this.devicenumber = devicenumber;
490 		this.ID = ID;
491 		this.devicetype = devicetype;
492 	}
493 	public bool conflKey(KeyBinding a){
494 		if(a.keycode == this.keycode && a.keymod == this.keymod && a.devicenumber == this.devicenumber && a.devicetype == this.devicetype){
495 			return true;
496 		}
497 		return false;
498 	}
499 	public bool conflID(KeyBinding a){
500 		if(a.ID == this.ID){
501 			return true;
502 		}
503 		return false;
504 	}
505 	bool opEquals(const KeyBinding s){
506 		if(s.keycode == this.keycode && s.keymod == this.keymod && s.devicenumber == this.devicenumber && s.devicetype == this.devicetype && s.ID == this.ID){
507 			return true;
508 		}
509 		return false;
510 	}
511 	string toString(){
512 		string s;
513 		s ~= "ID: ";
514 		s ~= ID;
515 		s ~= " Keycode: ";
516 		s ~= to!string(keycode);
517 		s ~= " Keymod: ";
518 		s ~= to!string(keymod);
519 		s ~= " Devicetype: ";
520 		s ~= to!string(devicetype);
521 		s ~= " Devicenumber: ";
522 		s ~= to!string(devicenumber);
523 		return s;
524 	}
525 }
526 
527 public interface InputListener{
528 	public void keyPressed(string ID, uint timestamp, uint devicenumber, uint devicetype);
529 	public void keyReleased(string ID, uint timestamp, uint devicenumber, uint devicetype);
530 }
531 
532 public interface AxisListener{
533 	public void axisEvent(string ID, uint timestamp, short val, uint devicenumber, uint devicetype);
534 }
535 
536 public interface MovementListener{
537 	public void movementEvent(string ID, short x, short y, short relX, short relY, uint devicenumber, uint devicetype);
538 }
539 
540 public interface MouseListener{
541 	public void mouseButtonEvent(uint which, uint timestamp, uint windowID, ubyte button, ubyte state, ubyte clicks, int x, int y);
542 	public void mouseWheelEvent(uint type, uint timestamp, uint windowID, uint which, int x, int y, int wX, int wY);
543 	public void mouseMotionEvent(uint timestamp, uint windowID, uint which, uint state, int x, int y, int relX, int relY);
544 }
545 
546 public interface TextInputListener{
547 	public void textInputEvent(uint timestamp, uint windowID, char[32] text);
548 	public void textInputKeyEvent(uint timestamp, uint windowID, InputKey key);
549 	public void dropTextInput();
550 }
551 
552 public interface TextInputHandler{
553 	public void startTextInput(string ID);
554 	public void stopTextInput(string ID);
555 	public void addTextInputListener(string ID, TextInputListener til);
556 }
557 
558 public interface SystemEventListener{
559 	public void onQuit();
560 	public void controllerRemoved(uint ID);
561 	public void controllerAdded(uint ID);
562 }
563 
564 public enum Devicetype{
565 	KEYBOARD	= 0,
566 	JOYSTICK	= 1,
567 	MOUSE		= 2,
568 	TOUCHSCREEN	= 3
569 }
570 
571 public enum InputKey{
572 	ENTER		= 1,
573 	ESCAPE		= 2,
574 	BACKSPACE	= 3,
575 	CURSORUP	= 4,
576 	CURSORDOWN	= 5,
577 	CURSORLEFT	= 6,
578 	CURSORRIGHT	= 7,
579 	INSERT		= 8,
580 	DELETE		= 9,
581 	HOME		= 10,
582 	END			= 11,
583 	PAGEUP		= 12,
584 	PAGEDOWN	= 13
585 }