1 /**
2     Event
3 
4     Copyright: (c) Enalye 2017
5     License: Zlib
6     Authors: Enalye
7 */
8 
9 module atelier.common.event;
10 
11 import std.path;
12 import std..string;
13 import std.conv;
14 import std.utf;
15 
16 version (linux) {
17     import core.sys.posix.unistd;
18     import core.sys.posix.signal;
19 }
20 version (Windows) {
21     import core.stdc.signal;
22 }
23 
24 import bindbc.sdl;
25 
26 import atelier.render;
27 import atelier.ui;
28 import atelier.core;
29 
30 import atelier.common.settings;
31 import atelier.common.controller;
32 
33 static private {
34     bool[KeyButton.max + 1] _keys1, _keys2;
35     bool[MouseButton.max + 1] _buttons1, _buttons2;
36     Vec2f _mousePosition;
37     Event[] _globalEvents;
38 }
39 
40 private shared bool _isRunning = false;
41 
42 /// List of mouse buttons.
43 enum MouseButton : ubyte {
44     left = SDL_BUTTON_LEFT,
45     middle = SDL_BUTTON_MIDDLE,
46     right = SDL_BUTTON_RIGHT,
47     x1 = SDL_BUTTON_X1,
48     x2 = SDL_BUTTON_X2,
49 }
50 
51 /// List of keyboard buttons.
52 enum KeyButton {
53     unknown = SDL_SCANCODE_UNKNOWN,
54     a = SDL_SCANCODE_A,
55     b = SDL_SCANCODE_B,
56     c = SDL_SCANCODE_C,
57     d = SDL_SCANCODE_D,
58     e = SDL_SCANCODE_E,
59     f = SDL_SCANCODE_F,
60     g = SDL_SCANCODE_G,
61     h = SDL_SCANCODE_H,
62     i = SDL_SCANCODE_I,
63     j = SDL_SCANCODE_J,
64     k = SDL_SCANCODE_K,
65     l = SDL_SCANCODE_L,
66     m = SDL_SCANCODE_M,
67     n = SDL_SCANCODE_N,
68     o = SDL_SCANCODE_O,
69     p = SDL_SCANCODE_P,
70     q = SDL_SCANCODE_Q,
71     r = SDL_SCANCODE_R,
72     s = SDL_SCANCODE_S,
73     t = SDL_SCANCODE_T,
74     u = SDL_SCANCODE_U,
75     v = SDL_SCANCODE_V,
76     w = SDL_SCANCODE_W,
77     x = SDL_SCANCODE_X,
78     y = SDL_SCANCODE_Y,
79     z = SDL_SCANCODE_Z,
80     alpha1 = SDL_SCANCODE_1,
81     alpha2 = SDL_SCANCODE_2,
82     alpha3 = SDL_SCANCODE_3,
83     alpha4 = SDL_SCANCODE_4,
84     alpha5 = SDL_SCANCODE_5,
85     alpha6 = SDL_SCANCODE_6,
86     alpha7 = SDL_SCANCODE_7,
87     alpha8 = SDL_SCANCODE_8,
88     alpha9 = SDL_SCANCODE_9,
89     alpha0 = SDL_SCANCODE_0,
90     enter = SDL_SCANCODE_RETURN,
91     escape = SDL_SCANCODE_ESCAPE,
92     backspace = SDL_SCANCODE_BACKSPACE,
93     tab = SDL_SCANCODE_TAB,
94     space = SDL_SCANCODE_SPACE,
95     minus = SDL_SCANCODE_MINUS,
96     equals = SDL_SCANCODE_EQUALS,
97     leftBracket = SDL_SCANCODE_LEFTBRACKET,
98     rightBracket = SDL_SCANCODE_RIGHTBRACKET,
99     backslash = SDL_SCANCODE_BACKSLASH,
100     nonushash = SDL_SCANCODE_NONUSHASH,
101     semicolon = SDL_SCANCODE_SEMICOLON,
102     apostrophe = SDL_SCANCODE_APOSTROPHE,
103     grave = SDL_SCANCODE_GRAVE,
104     comma = SDL_SCANCODE_COMMA,
105     period = SDL_SCANCODE_PERIOD,
106     slash = SDL_SCANCODE_SLASH,
107     capslock = SDL_SCANCODE_CAPSLOCK,
108     f1 = SDL_SCANCODE_F1,
109     f2 = SDL_SCANCODE_F2,
110     f3 = SDL_SCANCODE_F3,
111     f4 = SDL_SCANCODE_F4,
112     f5 = SDL_SCANCODE_F5,
113     f6 = SDL_SCANCODE_F6,
114     f7 = SDL_SCANCODE_F7,
115     f8 = SDL_SCANCODE_F8,
116     f9 = SDL_SCANCODE_F9,
117     f10 = SDL_SCANCODE_F10,
118     f11 = SDL_SCANCODE_F11,
119     f12 = SDL_SCANCODE_F12,
120     printScreen = SDL_SCANCODE_PRINTSCREEN,
121     scrollLock = SDL_SCANCODE_SCROLLLOCK,
122     pause = SDL_SCANCODE_PAUSE,
123     insert = SDL_SCANCODE_INSERT,
124     home = SDL_SCANCODE_HOME,
125     pageup = SDL_SCANCODE_PAGEUP,
126     remove = SDL_SCANCODE_DELETE,
127     end = SDL_SCANCODE_END,
128     pagedown = SDL_SCANCODE_PAGEDOWN,
129     right = SDL_SCANCODE_RIGHT,
130     left = SDL_SCANCODE_LEFT,
131     down = SDL_SCANCODE_DOWN,
132     up = SDL_SCANCODE_UP,
133     numLockclear = SDL_SCANCODE_NUMLOCKCLEAR,
134     numDivide = SDL_SCANCODE_KP_DIVIDE,
135     numMultiply = SDL_SCANCODE_KP_MULTIPLY,
136     numMinus = SDL_SCANCODE_KP_MINUS,
137     numPlus = SDL_SCANCODE_KP_PLUS,
138     numEnter = SDL_SCANCODE_KP_ENTER,
139     num1 = SDL_SCANCODE_KP_1,
140     num2 = SDL_SCANCODE_KP_2,
141     num3 = SDL_SCANCODE_KP_3,
142     num4 = SDL_SCANCODE_KP_4,
143     num5 = SDL_SCANCODE_KP_5,
144     num6 = SDL_SCANCODE_KP_6,
145     num7 = SDL_SCANCODE_KP_7,
146     num8 = SDL_SCANCODE_KP_8,
147     num9 = SDL_SCANCODE_KP_9,
148     num0 = SDL_SCANCODE_KP_0,
149     numPeriod = SDL_SCANCODE_KP_PERIOD,
150     nonusBackslash = SDL_SCANCODE_NONUSBACKSLASH,
151     application = SDL_SCANCODE_APPLICATION,
152     power = SDL_SCANCODE_POWER,
153     numEquals = SDL_SCANCODE_KP_EQUALS,
154     f13 = SDL_SCANCODE_F13,
155     f14 = SDL_SCANCODE_F14,
156     f15 = SDL_SCANCODE_F15,
157     f16 = SDL_SCANCODE_F16,
158     f17 = SDL_SCANCODE_F17,
159     f18 = SDL_SCANCODE_F18,
160     f19 = SDL_SCANCODE_F19,
161     f20 = SDL_SCANCODE_F20,
162     f21 = SDL_SCANCODE_F21,
163     f22 = SDL_SCANCODE_F22,
164     f23 = SDL_SCANCODE_F23,
165     f24 = SDL_SCANCODE_F24,
166     execute = SDL_SCANCODE_EXECUTE,
167     help = SDL_SCANCODE_HELP,
168     menu = SDL_SCANCODE_MENU,
169     select = SDL_SCANCODE_SELECT,
170     stop = SDL_SCANCODE_STOP,
171     again = SDL_SCANCODE_AGAIN,
172     undo = SDL_SCANCODE_UNDO,
173     cut = SDL_SCANCODE_CUT,
174     copy = SDL_SCANCODE_COPY,
175     paste = SDL_SCANCODE_PASTE,
176     find = SDL_SCANCODE_FIND,
177     mute = SDL_SCANCODE_MUTE,
178     volumeUp = SDL_SCANCODE_VOLUMEUP,
179     volumeDown = SDL_SCANCODE_VOLUMEDOWN,
180     numComma = SDL_SCANCODE_KP_COMMA,
181     numEqualsAs400 = SDL_SCANCODE_KP_EQUALSAS400,
182     international1 = SDL_SCANCODE_INTERNATIONAL1,
183     international2 = SDL_SCANCODE_INTERNATIONAL2,
184     international3 = SDL_SCANCODE_INTERNATIONAL3,
185     international4 = SDL_SCANCODE_INTERNATIONAL4,
186     international5 = SDL_SCANCODE_INTERNATIONAL5,
187     international6 = SDL_SCANCODE_INTERNATIONAL6,
188     international7 = SDL_SCANCODE_INTERNATIONAL7,
189     international8 = SDL_SCANCODE_INTERNATIONAL8,
190     international9 = SDL_SCANCODE_INTERNATIONAL9,
191     lang1 = SDL_SCANCODE_LANG1,
192     lang2 = SDL_SCANCODE_LANG2,
193     lang3 = SDL_SCANCODE_LANG3,
194     lang4 = SDL_SCANCODE_LANG4,
195     lang5 = SDL_SCANCODE_LANG5,
196     lang6 = SDL_SCANCODE_LANG6,
197     lang7 = SDL_SCANCODE_LANG7,
198     lang8 = SDL_SCANCODE_LANG8,
199     lang9 = SDL_SCANCODE_LANG9,
200     alterase = SDL_SCANCODE_ALTERASE,
201     sysreq = SDL_SCANCODE_SYSREQ,
202     cancel = SDL_SCANCODE_CANCEL,
203     clear = SDL_SCANCODE_CLEAR,
204     prior = SDL_SCANCODE_PRIOR,
205     enter2 = SDL_SCANCODE_RETURN2,
206     separator = SDL_SCANCODE_SEPARATOR,
207     out_ = SDL_SCANCODE_OUT,
208     oper = SDL_SCANCODE_OPER,
209     clearAgain = SDL_SCANCODE_CLEARAGAIN,
210     crsel = SDL_SCANCODE_CRSEL,
211     exsel = SDL_SCANCODE_EXSEL,
212     num00 = SDL_SCANCODE_KP_00,
213     num000 = SDL_SCANCODE_KP_000,
214     thousandSeparator = SDL_SCANCODE_THOUSANDSSEPARATOR,
215     decimalSeparator = SDL_SCANCODE_DECIMALSEPARATOR,
216     currencyUnit = SDL_SCANCODE_CURRENCYUNIT,
217     currencySubunit = SDL_SCANCODE_CURRENCYSUBUNIT,
218     numLeftParenthesis = SDL_SCANCODE_KP_LEFTPAREN,
219     numRightParenthesis = SDL_SCANCODE_KP_RIGHTPAREN,
220     numLeftBrace = SDL_SCANCODE_KP_LEFTBRACE,
221     numRightBrace = SDL_SCANCODE_KP_RIGHTBRACE,
222     numTab = SDL_SCANCODE_KP_TAB,
223     numBackspace = SDL_SCANCODE_KP_BACKSPACE,
224     numA = SDL_SCANCODE_KP_A,
225     numB = SDL_SCANCODE_KP_B,
226     numC = SDL_SCANCODE_KP_C,
227     numD = SDL_SCANCODE_KP_D,
228     numE = SDL_SCANCODE_KP_E,
229     numF = SDL_SCANCODE_KP_F,
230     numXor = SDL_SCANCODE_KP_XOR,
231     numPower = SDL_SCANCODE_KP_POWER,
232     numPercent = SDL_SCANCODE_KP_PERCENT,
233     numLess = SDL_SCANCODE_KP_LESS,
234     numGreater = SDL_SCANCODE_KP_GREATER,
235     numAmpersand = SDL_SCANCODE_KP_AMPERSAND,
236     numDblAmpersand = SDL_SCANCODE_KP_DBLAMPERSAND,
237     numVerticalBar = SDL_SCANCODE_KP_VERTICALBAR,
238     numDblVerticalBar = SDL_SCANCODE_KP_DBLVERTICALBAR,
239     numColon = SDL_SCANCODE_KP_COLON,
240     numHash = SDL_SCANCODE_KP_HASH,
241     numSpace = SDL_SCANCODE_KP_SPACE,
242     numAt = SDL_SCANCODE_KP_AT,
243     numExclam = SDL_SCANCODE_KP_EXCLAM,
244     numMemStore = SDL_SCANCODE_KP_MEMSTORE,
245     numMemRecall = SDL_SCANCODE_KP_MEMRECALL,
246     numMemClear = SDL_SCANCODE_KP_MEMCLEAR,
247     numMemAdd = SDL_SCANCODE_KP_MEMADD,
248     numMemSubtract = SDL_SCANCODE_KP_MEMSUBTRACT,
249     numMemMultiply = SDL_SCANCODE_KP_MEMMULTIPLY,
250     numMemDivide = SDL_SCANCODE_KP_MEMDIVIDE,
251     numPlusMinus = SDL_SCANCODE_KP_PLUSMINUS,
252     numClear = SDL_SCANCODE_KP_CLEAR,
253     numClearEntry = SDL_SCANCODE_KP_CLEARENTRY,
254     numBinary = SDL_SCANCODE_KP_BINARY,
255     numOctal = SDL_SCANCODE_KP_OCTAL,
256     numDecimal = SDL_SCANCODE_KP_DECIMAL,
257     numHexadecimal = SDL_SCANCODE_KP_HEXADECIMAL,
258     leftControl = SDL_SCANCODE_LCTRL,
259     leftShift = SDL_SCANCODE_LSHIFT,
260     leftAlt = SDL_SCANCODE_LALT,
261     leftGUI = SDL_SCANCODE_LGUI,
262     rightControl = SDL_SCANCODE_RCTRL,
263     rightShift = SDL_SCANCODE_RSHIFT,
264     rightAlt = SDL_SCANCODE_RALT,
265     rightGUI = SDL_SCANCODE_RGUI,
266     mode = SDL_SCANCODE_MODE,
267     audioNext = SDL_SCANCODE_AUDIONEXT,
268     audioPrev = SDL_SCANCODE_AUDIOPREV,
269     audioStop = SDL_SCANCODE_AUDIOSTOP,
270     audioPlay = SDL_SCANCODE_AUDIOPLAY,
271     audioMute = SDL_SCANCODE_AUDIOMUTE,
272     mediaSelect = SDL_SCANCODE_MEDIASELECT,
273     www = SDL_SCANCODE_WWW,
274     mail = SDL_SCANCODE_MAIL,
275     calculator = SDL_SCANCODE_CALCULATOR,
276     computer = SDL_SCANCODE_COMPUTER,
277     acSearch = SDL_SCANCODE_AC_SEARCH,
278     acHome = SDL_SCANCODE_AC_HOME,
279     acBack = SDL_SCANCODE_AC_BACK,
280     acForward = SDL_SCANCODE_AC_FORWARD,
281     acStop = SDL_SCANCODE_AC_STOP,
282     acRefresh = SDL_SCANCODE_AC_REFRESH,
283     acBookmarks = SDL_SCANCODE_AC_BOOKMARKS,
284     brightnessDown = SDL_SCANCODE_BRIGHTNESSDOWN,
285     brightnessUp = SDL_SCANCODE_BRIGHTNESSUP,
286     displaysWitch = SDL_SCANCODE_DISPLAYSWITCH,
287     kbdIllumToggle = SDL_SCANCODE_KBDILLUMTOGGLE,
288     kbdIllumDown = SDL_SCANCODE_KBDILLUMDOWN,
289     kbdIllumUp = SDL_SCANCODE_KBDILLUMUP,
290     eject = SDL_SCANCODE_EJECT,
291     sleep = SDL_SCANCODE_SLEEP,
292     app1 = SDL_SCANCODE_APP1,
293     app2 = SDL_SCANCODE_APP2
294 }
295 
296 /// Event structure passed on onEvent() methods.
297 struct Event {
298     /// Type of event
299     enum Type : uint {
300         keyUp,
301         keyDown,
302         keyInput,
303         keyDelete,
304         keyEnter,
305         keyDir,
306         mouseUp,
307         mouseDown,
308         mouseUpdate,
309         mouseWheel,
310         quit,
311         dropFile,
312         resize,
313         modalOpen,
314         modalClose,
315         modalApply,
316         modalCancel,
317         callback,
318         custom
319     }
320 
321     /// Ctor from basic type.
322     this(Type type_) {
323         type = type_;
324     }
325 
326     /// Base type.
327     Event.Type type;
328     union {
329         /// For base type `keyDown` and `keyUp`.
330         KeyEvent key;
331         /// For base type `mouseDown`, `mouseUp` and `mouseUpdate`.
332         MouseEvent mouse;
333         /// For base type `mouseWheel`.
334         MouseWheelEvent scroll;
335         /// For base type `keyInput`.
336         TextInputEvent input;
337         /// For base type `dropFile`.
338         DropFileEvent drop;
339         /// For base type `keyDelete`.
340         TextDeleteEvent textDelete;
341         /// For base type `keyDir`.
342         KeyMoveEvent keyMove;
343         /// For base type `resize`.
344         WindowEvent window;
345         /// For base type `custom`.
346         CustomEvent custom;
347     }
348 
349     /// For base type `keyDown` and `keyUp`.
350     struct KeyEvent {
351         /// Which button was active
352         KeyButton button;
353         /// Was it repeated
354         bool isRepeated;
355     }
356 
357     /// For base type `mouseDown`, `mouseUp` and `mouseUpdate`.
358     struct MouseEvent {
359         /// Mouse position relative to its canvas. (Not an absolute position)
360         Vec2f position;
361         /// Button pressed or not.
362         MouseButton button;
363         /// How many time the button was pressed.
364         uint clicks;
365     }
366 
367     /// For base type `mouseWheel`.
368     struct MouseWheelEvent {
369         /// Direction of scrolling.
370         Vec2f delta;
371     }
372 
373     /// For base type `dropFile`.
374     struct DropFileEvent {
375         /// Full path of the file dropped.
376         string filePath;
377     }
378 
379     /// For base type `keyInput`.
380     struct TextInputEvent {
381         /// Text written by the user.
382         string text;
383     }
384 
385     /// For base type `keyDelete`.
386     struct TextDeleteEvent {
387         /// 1 = delete right char, \
388         /// -1 = delete left char.
389         int direction;
390     }
391 
392     /// For base type `keyDir`.
393     struct KeyMoveEvent {
394         /// Arrow keys movement.
395         Vec2f direction;
396     }
397 
398     /// For base type `resize`.
399     struct WindowEvent {
400         /// New size of the window.
401         Vec2i size;
402     }
403 
404     /// Custom event
405     struct CustomEvent {
406         /// Identifier
407         string id;
408         /// User defined data
409         void* data;
410     }
411 }
412 
413 /// Check whether the key associated with the ID is pressed. \
414 /// Do not reset the value.
415 bool isButtonDown(KeyButton button) {
416     return _keys1[button];
417 }
418 
419 /// Check whether the key associated with the ID is pressed. \
420 /// This function resets the value to false.
421 bool getButtonDown(KeyButton button) {
422     const bool value = _keys2[button];
423     _keys2[button] = false;
424     return value;
425 }
426 
427 /// Check whether the mouse button associated with the ID is pressed. \
428 /// Do not reset the value.
429 bool isButtonDown(MouseButton button) {
430     return _buttons1[button];
431 }
432 
433 /// Check whether the mouse button associated with the ID is pressed. \
434 /// This function resets the value to false.
435 bool getButtonDown(MouseButton button) {
436     const bool value = _buttons2[button];
437     _buttons2[button] = false;
438     return value;
439 }
440 
441 /// Returns the position of the mouse relative to the window.
442 Vec2f getMousePos() {
443     return _mousePosition;
444 }
445 
446 /// Tells the application to finish.
447 void stopApplication() {
448     _isRunning = false;
449 }
450 
451 /// Check if the application's still running.
452 bool isRunning() {
453     return _isRunning;
454 }
455 
456 /// Dispatch an event to GUIs.
457 void sendEvent(Event.Type eventType) {
458     Event event = Event(eventType);
459     _globalEvents ~= event;
460 }
461 
462 /// Dispatch an event to GUIs.
463 void sendEvent(Event event) {
464     _globalEvents ~= event;
465 }
466 
467 /// Send a custom event.
468 void sendCustomEvent(string id, void* data = null) {
469     Event event;
470     event.type = Event.Type.custom;
471     event.custom.id = id;
472     event.custom.data = data;
473     _globalEvents ~= event;
474 }
475 
476 /// Capture interruptions.
477 extern (C) void signalHandler(int sig) nothrow @nogc @system {
478     cast(void) sig;
479     _isRunning = false;
480 }
481 
482 /// Initialize everything mouse, keyboard or controller related.
483 void initializeEvents() {
484     signal(SIGINT, &signalHandler);
485     _isRunning = true;
486     _mousePosition = Vec2f.zero;
487     initializeControllers();
488 }
489 
490 /// Closes everything mouse, keyboard or controller related.
491 void destroyEvents() {
492     destroyControllers();
493 }
494 
495 /// Updates everything mouse, keyboard or controller related.
496 void updateEvents(float deltaTime) {
497     updateControllers(deltaTime);
498 }
499 
500 /// Process and dispatch window, input, etc events.
501 bool processEvents() {
502     Event event;
503     SDL_Event sdlEvent;
504 
505     if (!_isRunning) {
506         event.type = Event.Type.quit;
507         handleGuiElementEvent(event);
508         destroyWindow();
509         return false;
510     }
511 
512     //Used to start receiving SDL_TEXTINPUT events
513     //SDL_StartTextInput();
514 
515     while (SDL_PollEvent(&sdlEvent)) {
516         switch (sdlEvent.type) {
517         case SDL_QUIT:
518             _isRunning = false;
519             event.type = Event.Type.quit;
520             handleGuiElementEvent(event);
521             destroyWindow();
522             //No operation involving the SDL after this.
523             return false;
524         case SDL_KEYDOWN:
525             if (sdlEvent.key.keysym.scancode >= _keys1.length)
526                 break;
527             if (!sdlEvent.key.repeat) {
528                 _keys1[sdlEvent.key.keysym.scancode] = true;
529                 _keys2[sdlEvent.key.keysym.scancode] = true;
530             }
531 
532             { // KeyDown Event
533                 event.type = Event.Type.keyDown;
534                 event.key.button = cast(KeyButton) sdlEvent.key.keysym.scancode;
535                 event.key.isRepeated = sdlEvent.key.repeat > 0;
536                 handleGuiElementEvent(event);
537             }
538             switch (sdlEvent.key.keysym.scancode) {
539             case SDL_SCANCODE_DELETE:
540                 event.type = Event.Type.keyDelete;
541                 event.textDelete.direction = 1;
542                 handleGuiElementEvent(event);
543                 break;
544             case SDL_SCANCODE_BACKSPACE:
545                 event.type = Event.Type.keyDelete;
546                 event.textDelete.direction = -1;
547                 handleGuiElementEvent(event);
548                 break;
549             case SDL_SCANCODE_RETURN:
550                 event.type = Event.Type.keyEnter;
551                 handleGuiElementEvent(event);
552                 break;
553             case SDL_SCANCODE_UP:
554                 event.type = Event.Type.keyDir;
555                 event.keyMove.direction = Vec2f(0f, -1f);
556                 handleGuiElementEvent(event);
557                 break;
558             case SDL_SCANCODE_DOWN:
559                 event.type = Event.Type.keyDir;
560                 event.keyMove.direction = Vec2f(0f, 1f);
561                 handleGuiElementEvent(event);
562                 break;
563             case SDL_SCANCODE_LEFT:
564                 event.type = Event.Type.keyDir;
565                 event.keyMove.direction = Vec2f(-1f, 0f);
566                 handleGuiElementEvent(event);
567                 break;
568             case SDL_SCANCODE_RIGHT:
569                 event.type = Event.Type.keyDir;
570                 event.keyMove.direction = Vec2f(1f, 0f);
571                 handleGuiElementEvent(event);
572                 break;
573             default:
574                 break;
575             }
576             break;
577         case SDL_KEYUP:
578             if (sdlEvent.key.keysym.scancode >= _keys1.length)
579                 break;
580             _keys1[sdlEvent.key.keysym.scancode] = false;
581             _keys2[sdlEvent.key.keysym.scancode] = false;
582 
583             { // KeyUp Event
584                 event.type = Event.Type.keyUp;
585                 event.key.button = cast(KeyButton) sdlEvent.key.keysym.scancode;
586                 event.key.isRepeated = sdlEvent.key.repeat > 0;
587                 handleGuiElementEvent(event);
588             }
589             break;
590         case SDL_TEXTINPUT:
591             string text = to!string(sdlEvent.text.text);
592             text.length = stride(text);
593             event.type = Event.Type.keyInput;
594             event.input.text = text;
595             handleGuiElementEvent(event);
596             break;
597         case SDL_MOUSEMOTION:
598             _mousePosition.set(cast(float) sdlEvent.motion.x, cast(float) sdlEvent.motion.y);
599             _mousePosition = transformCanvasSpace(_mousePosition);
600 
601             event.type = Event.Type.mouseUpdate;
602             event.mouse.position = _mousePosition;
603 
604             handleGuiElementEvent(event);
605             break;
606         case SDL_MOUSEBUTTONDOWN:
607             _mousePosition.set(cast(float) sdlEvent.motion.x, cast(float) sdlEvent.motion.y);
608             _mousePosition = transformCanvasSpace(_mousePosition);
609             if (sdlEvent.button.button >= _buttons1.length)
610                 break;
611             _buttons1[sdlEvent.button.button] = true;
612             _buttons2[sdlEvent.button.button] = true;
613 
614             event.type = Event.Type.mouseDown;
615             event.mouse.position = _mousePosition;
616             event.mouse.button = cast(MouseButton) sdlEvent.button.button;
617             event.mouse.clicks = sdlEvent.button.clicks;
618 
619             handleGuiElementEvent(event);
620             break;
621         case SDL_MOUSEBUTTONUP:
622             _mousePosition.set(cast(float) sdlEvent.motion.x, cast(float) sdlEvent.motion.y);
623             _mousePosition = transformCanvasSpace(_mousePosition);
624             if (sdlEvent.button.button >= _buttons1.length)
625                 break;
626             _buttons1[sdlEvent.button.button] = false;
627             _buttons2[sdlEvent.button.button] = false;
628 
629             event.type = Event.Type.mouseUp;
630             event.mouse.position = _mousePosition;
631             event.mouse.button = cast(MouseButton) sdlEvent.button.button;
632             event.mouse.clicks = sdlEvent.button.clicks;
633 
634             handleGuiElementEvent(event);
635             break;
636         case SDL_MOUSEWHEEL:
637             event.type = Event.Type.mouseWheel;
638             event.scroll.delta = Vec2f(sdlEvent.wheel.x, sdlEvent.wheel.y);
639             handleGuiElementEvent(event);
640             break;
641         case SDL_WINDOWEVENT:
642             switch (sdlEvent.window.event) {
643             case SDL_WINDOWEVENT_RESIZED:
644                 event.type = Event.Type.resize;
645                 event.window.size = Vec2i(sdlEvent.window.data1, sdlEvent.window.data2);
646                 resizeWindow(event.window.size);
647                 handleGuiElementEvent(event);
648                 break;
649             case SDL_WINDOWEVENT_SIZE_CHANGED:
650                 break;
651             default:
652                 break;
653             }
654             break;
655         case SDL_DROPFILE:
656             string path = to!string(fromStringz(sdlEvent.drop.file));
657             size_t index;
658             while (-1 != (index = path.indexOfAny("%"))) {
659                 if ((index + 3) > path.length)
660                     break;
661                 string str = path[index + 1 .. index + 3];
662                 const int utfValue = parse!int(str, 16);
663                 const char utfChar = to!char(utfValue);
664 
665                 if (index == 0)
666                     path = utfChar ~ path[3 .. $];
667                 else if ((index + 3) == path.length)
668                     path = path[0 .. index] ~ utfChar;
669                 else
670                     path = path[0 .. index] ~ utfChar ~ path[index + 3 .. $];
671             }
672 
673             event.type = Event.Type.dropFile;
674             event.drop.filePath = path;
675             handleGuiElementEvent(event);
676 
677             SDL_free(sdlEvent.drop.file);
678             break;
679         case SDL_CONTROLLERDEVICEADDED:
680             addController(sdlEvent.cdevice.which);
681             break;
682         case SDL_CONTROLLERDEVICEREMOVED:
683             removeController(sdlEvent.cdevice.which);
684             break;
685         case SDL_CONTROLLERDEVICEREMAPPED:
686             remapController(sdlEvent.cdevice.which);
687             break;
688         case SDL_CONTROLLERAXISMOTION:
689             setControllerAxis(cast(SDL_GameControllerAxis) sdlEvent.caxis.axis,
690                     sdlEvent.caxis.value);
691             break;
692         case SDL_CONTROLLERBUTTONDOWN:
693             setControllerButton(cast(SDL_GameControllerButton) sdlEvent.cbutton.button, true);
694             break;
695         case SDL_CONTROLLERBUTTONUP:
696             setControllerButton(cast(SDL_GameControllerButton) sdlEvent.cbutton.button, false);
697             break;
698         default:
699             break;
700         }
701     }
702 
703     foreach (Event globalEvent; _globalEvents) {
704         switch (globalEvent.type) with (Event.Type) {
705         case quit:
706             _isRunning = false;
707             handleGuiElementEvent(globalEvent);
708             destroyWindow();
709             return false;
710         default:
711             handleGuiElementEvent(globalEvent);
712             break;
713         }
714     }
715     _globalEvents.length = 0;
716 
717     return true;
718 }
719 
720 /// Check if the clipboard isn't empty
721 bool hasClipboard() {
722     return cast(bool) SDL_HasClipboardText();
723 }
724 
725 /// Returns the content of the clipboard
726 string getClipboard() {
727     auto clipboard = SDL_GetClipboardText();
728     if (clipboard) {
729         string text = to!string(fromStringz(clipboard));
730         SDL_free(clipboard);
731         return text;
732     }
733     return "";
734 }
735 
736 /// Fill the clipboard
737 void setClipboard(string text) {
738     SDL_SetClipboardText(toStringz(text));
739 }