1 /*
2  *******************************************************************************************
3  * Dgame (a D game framework) - Copyright (c) Randy Schütt
4  * 
5  * This software is provided 'as-is', without any express or implied warranty.
6  * In no event will the authors be held liable for any damages arising from
7  * the use of this software.
8  * 
9  * Permission is granted to anyone to use this software for any purpose,
10  * including commercial applications, and to alter it and redistribute it
11  * freely, subject to the following restrictions:
12  * 
13  * 1. The origin of this software must not be misrepresented; you must not claim
14  *    that you wrote the original software. If you use this software in a product,
15  *    an acknowledgment in the product documentation would be appreciated but is
16  *    not required.
17  * 
18  * 2. Altered source versions must be plainly marked as such, and must not be
19  *    misrepresented as being the original software.
20  * 
21  * 3. This notice may not be removed or altered from any source distribution.
22  *******************************************************************************************
23  */
24 module Dgame.Window.Event;
25 
26 private:
27 
28 import derelict.sdl2.sdl;
29 
30 import Dgame.System.Mouse;
31 import Dgame.System.Keyboard;
32 import Dgame.System.Joystick;
33 import Dgame.System.GameController;
34 
35 public:
36 
37 /**
38  * The Window move Event structure.
39  */
40 struct WindowMoveEvent {
41     /**
42      * The new x position
43      */
44     int x;
45     /**
46      * The new y position
47      */
48     int y;
49 }
50 
51 /**
52  * The Window size Event structure.
53  */
54 struct WindowSizeEvent {
55     /**
56      * The new width
57      */
58     int width;
59     /**
60      * The new height
61      */
62     int height;
63 }
64 
65 /**
66  * The Window Event structure.
67  */
68 struct WindowEvent {
69     /**
70      * All supported Window Event Types
71      */
72     enum Type {
73         Shown = SDL_WINDOWEVENT_SHOWN,  /// Window has been shown
74         Hidden = SDL_WINDOWEVENT_HIDDEN, /// Window has been hidden
75         Exposed = SDL_WINDOWEVENT_EXPOSED,    /// Window has been exposed and should be redrawn
76         Moved = SDL_WINDOWEVENT_MOVED,  /// Window has been moved
77         Resized = SDL_WINDOWEVENT_RESIZED,    /// Window has been resized
78         SizeChanged = SDL_WINDOWEVENT_SIZE_CHANGED, /// Window size has changed; this event is followed by Type.Resized
79         Minimized = SDL_WINDOWEVENT_MINIMIZED,  /// Window has been minimized
80         Maximized = SDL_WINDOWEVENT_MAXIMIZED,  /// Window has been maximized
81         Restored = SDL_WINDOWEVENT_RESTORED,   /// Window has been restored to normal size and position
82         Enter = SDL_WINDOWEVENT_ENTER,  /// Window has gained mouse focus
83         Leave = SDL_WINDOWEVENT_LEAVE,  /// Window has lost mouse focus
84         FocusGained = SDL_WINDOWEVENT_FOCUS_GAINED,    /// Window has gained keyboard focus
85         FocusLost = SDL_WINDOWEVENT_FOCUS_LOST,  /// Window has lost keyboard focus
86         Close = SDL_WINDOWEVENT_CLOSE /// The window manager requests that the window be closed
87     }
88 
89     /**
90      * The Type of the Window Event
91      */
92     Type event;
93 
94     union {
95         WindowSizeEvent size; /// Size Event
96         WindowMoveEvent motion; /// Motion Event
97     }
98 }
99 
100 /**
101  * The Keyboard Event structure.
102  */
103 struct KeyboardEvent {
104     /**
105      * true, if the key is pressed
106      */
107     bool isPressed;
108     /**
109      * The Key which is released or pressed.
110      */
111     Keyboard.Key key;
112     /**
113      * The Key modifier.
114      */
115     Keyboard.Mod mod;
116     /**
117      * true, if this is a key repeat.
118      */
119     bool isRepeat;
120     /**
121      * An alias
122      */
123     deprecated("Use 'key' instead")
124     alias code = key;
125 }
126 
127 /**
128  * The Mouse button Event structure.
129  */
130 struct MouseButtonEvent {
131     /**
132      * The mouse button which is pressed or released.
133      */
134     Mouse.Button button;
135     /**
136      * true, if the button is pressed
137      */
138     bool isPressed;
139     /**
140      * 1 for single-click, 2 for double-click, etc.
141      */
142     ubyte clicks;
143     /**
144      * Current x position.
145      */
146     int x;
147     /**
148      * Current y position.
149      */
150     int y;
151 }
152 
153 /**
154  * The Mouse motion Event structure.
155  */
156 struct MouseMotionEvent {
157     /**
158      * true, if the button is pressed
159      */
160     bool isPressed;
161     /**
162      * Current x position.
163      */
164     int x;
165     /**
166      * Current y position.
167      */
168     int y;
169     /**
170      * Relative motion in the x direction.
171      */
172     int rel_x;
173     /**
174      * Relative motion in the y direction.
175      */
176     int rel_y;
177 }
178 
179 /**
180  * The Mouse wheel Event structure.
181  */
182 struct MouseWheelEvent {
183     /**
184      * The amount scrolled horizontally, positive to the right and negative to the left
185      */
186     int x;
187     /**
188      * The amount scrolled vertically, positive away from the user and negative toward the user
189      */
190     int y;
191 
192 static if (SDL_VERSION_ATLEAST(2, 0, 4)) {
193     /**
194      * If true, the values in x and y will be opposite. Multiply by -1 to change them back.
195      */
196     bool isFlipped;
197 }
198 }
199 
200 /**
201  * The Joystick axis motion Event structure
202  */
203 struct JoystickAxisEvent {
204     /**
205      * The instance id of the joystick which reported the event
206      */
207     int which;
208     /**
209      * The index of the axis that changed
210      * Typically 0 is the x axis, 1 is the y axis etc.
211      */
212     ubyte axis;
213     /**
214      * The current position of the axis (range: -32768 to 32767)
215      */
216     short value;
217 }
218 
219 /**
220  * The Joystick button Event structure
221  */
222 struct JoystickButtonEvent {
223     /**
224      * The instance id of the joystick which reported the event
225      */
226     int which;
227     /**
228      * The index of the button which is pressed or released
229      */
230     ubyte button;
231     /**
232      * true, if the button is pressed
233      */
234     bool isPressed;
235 }
236 
237 /**
238  * The Joystick hat Event structure
239  */
240 struct JoystickHatEvent {
241     /**
242      * The instance id of the joystick which reported the event
243      */
244     int which;
245     /**
246      * The index of the hat that changed
247      */
248     ubyte hat;
249     /**
250      * The new position of the hat
251      *
252      * See Joystick.Hat enum
253      */
254     Joystick.Hat value;
255 }
256 
257 /**
258  * The Joystick device Event structure
259  */
260 struct JoystickDeviceEvent {
261     /**
262      * The instance id of the joystick which reported the event
263      */
264     int which;
265 }
266 
267 /**
268  * The Game Controller axis Event structure
269  */
270 struct ControllerAxisEvent {
271     /**
272      * The instance id of the joystick which reported the event
273      */
274     int which;
275     /**
276      * The index of the axis that changed
277      * Typically 0 is the x axis, 1 is the y axis etc.
278      */
279     GameController.Axis axis;
280     /**
281      * The current position of the axis (range: -32768 to 32767)
282      */
283     short value;
284 }
285 
286 /**
287  * The Game Controller button Event structure
288  */
289 struct ControllerButtonEvent {
290     /**
291      * The instance id of the joystick which reported the event
292      */
293     int which;
294     /**
295      * The GameController button which is pressed or released
296      */
297     GameController.Button button;
298     /**
299      * true, if the button is pressed
300      */
301     bool isPressed;
302 }
303 
304 /**
305  * The Game Controller device Event structure
306  */
307 struct ControllerDeviceEvent {
308     /**
309      * The instance id of the joystick which reported the event
310      */
311     int which;
312 }
313 
314 /**
315  * The Finger Touch Event structure
316  */
317 struct TouchFingerEvent {
318     /**
319      * The id of the touch device
320      */
321     long touchId;
322     /**
323      * The id of the finger who touched the device
324      */
325     long fingerId;
326     /**
327      * The x coordinate of the touch event, in range of 0 .. 1
328      * Multiply it with the width if the Window to get the real x coordinate
329      */
330     float x;
331     /**
332      * The y coordinate of the touch event, in range of 0 .. 1
333      * Multiply it with the height if the Window to get the real y coordinate
334      */
335     float y;
336     /**
337      * The distance of the x coordinate (since the last event) in range of 0 .. 1
338      */
339     float dx;
340     /**
341      * The distance of the y coordinate (since the last event) in range of 0 .. 1
342      */
343     float dy;
344     /**
345      * The quantity of pressure applied in range of 0 .. 1
346      */
347     float pressure;
348 }
349 
350 /**
351  * Mouse union
352  */
353 union MouseUnion {
354     MouseButtonEvent button; /// Mouse button Event
355     MouseMotionEvent motion; /// Mouse motion Event
356     MouseWheelEvent  wheel; /// Mouse wheel Event
357 }
358 
359 /**
360  * Joystick union
361  */
362 union JoystickUnion {
363     JoystickAxisEvent motion; /// Joystick motion Event
364     JoystickButtonEvent button; /// Joystick button Event
365     JoystickHatEvent hat; /// Joystick hat Event
366     JoystickDeviceEvent device; /// Joystick device Event
367 }
368 
369 /**
370  * Game Controller union
371  */
372 union ControllerUnion {
373     ControllerAxisEvent motion; /// Controller motion Event
374     ControllerButtonEvent button; /// Controller button Event
375     ControllerDeviceEvent device; /// Controller device Event
376 }
377 
378 /**
379  * The Event structure.
380  * Event defines a system event and it's parameters
381  *
382  * Author: Randy Schuett (rswhite4@googlemail.com)
383  */
384 struct Event {
385     /**
386      * All supported Event Types.
387      */
388     enum Type {
389         Quit = SDL_QUIT,    /// Quit Event. Time to close the window.
390 
391         Window = SDL_WINDOWEVENT,  /// Something happens with the window.
392 
393         KeyDown = SDL_KEYDOWN,  /// A key is pressed.
394         KeyUp = SDL_KEYUP,  /// A key is released.
395 
396         MouseMotion = SDL_MOUSEMOTION,  /// The mouse has moved.
397         MouseButtonDown = SDL_MOUSEBUTTONDOWN,  /// A mouse button is pressed.
398         MouseButtonUp = SDL_MOUSEBUTTONUP,  /// A mouse button is released.
399         MouseWheel = SDL_MOUSEWHEEL,    /// The mouse wheel has scolled.
400 
401         JoystickAxisMotion = SDL_JOYAXISMOTION, /// A Joystick axis has moved
402         JoystickButtonDown = SDL_JOYBUTTONDOWN, /// A Joystick button is pressed
403         JoystickButtonUp = SDL_JOYBUTTONUP,  /// A Joystick button is released
404         JoystickHatMotion = SDL_JOYHATMOTION, /// A Joystick hat has moved
405         JoystickDeviceAdded = SDL_JOYDEVICEADDED, /// A Joystick was added
406         JoystickDeviceRemoved = SDL_JOYDEVICEREMOVED, /// A Joystick was removed
407         
408         ControllerAxisMotion = SDL_CONTROLLERAXISMOTION, /// A GameController axis has moved
409         ControllerButtonDown = SDL_CONTROLLERBUTTONDOWN, /// A GameController button is pressed
410         ControllerButtonUp = SDL_CONTROLLERBUTTONUP,  /// A GameController button is released
411         ControllerDeviceAdded = SDL_CONTROLLERDEVICEADDED, /// A GameController was added
412         ControllerDeviceRemoved = SDL_CONTROLLERDEVICEREMOVED, /// A GameController was removed
413         ControllerDeviceMapped = SDL_CONTROLLERDEVICEREMAPPED, /// A GameController was mapped
414 
415         FingerMotion = SDL_FINGERMOTION, /// A finger was moved onto the touch device
416         FingerDown = SDL_FINGERDOWN, /// A finger is pressed onto the touch device
417         FingerUp = SDL_FINGERUP, /// A finger is released of the touch device
418     }
419 
420     /**
421      * The type of the Event
422      */
423     Type type;
424     /**
425      * Milliseconds since the app is running
426      */
427     uint timestamp;
428     /**
429      * The window which has raised this event
430      */
431     uint windowId;
432     
433     union {
434         KeyboardEvent keyboard; /// Keyboard Event
435         WindowEvent window; /// Window Event
436         MouseUnion mouse; /// Mouse Events
437         JoystickUnion joystick; /// Joystick Events
438         ControllerUnion controller; /// Controller Events
439         TouchFingerEvent fingerTouch; /// Finger-Touch Events
440     }
441 }
442 
443 package:
444 
445 @nogc
446 bool _translate(Event* event, ref const SDL_Event sdl_event) nothrow {
447     assert(event, "Event is null");
448 
449     switch (sdl_event.type) {
450         case Event.Type.KeyDown:
451         case Event.Type.KeyUp:
452             event.type = cast(Event.Type) sdl_event.type;
453             event.timestamp = sdl_event.key.timestamp;
454             event.windowId = sdl_event.key.windowID;
455             event.keyboard.isPressed = sdl_event.key.state == SDL_PRESSED;
456             event.keyboard.key = cast(Keyboard.Key) sdl_event.key.keysym.sym;
457             event.keyboard.isRepeat = sdl_event.key.repeat != 0;
458             event.keyboard.mod = Keyboard.getModifier();
459 
460             return true;
461         case Event.Type.Window:
462             event.type = Event.Type.Window;
463             event.windowId = sdl_event.window.windowID;
464             event.timestamp = sdl_event.window.timestamp;
465             
466             switch (sdl_event.window.event) {
467                 case WindowEvent.Type.Moved:
468                     event.window.motion.x = sdl_event.window.data1;
469                     event.window.motion.y = sdl_event.window.data2;
470 
471                     break;
472                 case WindowEvent.Type.Resized:
473                     event.window.size.width = sdl_event.window.data1;
474                     event.window.size.height = sdl_event.window.data2;
475 
476                     break;
477                 default: break;
478             }
479 
480             event.window.event = cast(WindowEvent.Type) sdl_event.window.event;
481             
482             return true;
483         case Event.Type.Quit:
484             event.type = Event.Type.Quit;
485             
486             return true;
487         case Event.Type.MouseButtonDown:
488         case Event.Type.MouseButtonUp:
489             event.type = cast(Event.Type) sdl_event.type;
490             event.timestamp = sdl_event.button.timestamp;
491             event.windowId  = sdl_event.button.windowID;
492             event.mouse.button.isPressed = sdl_event.button.state == SDL_PRESSED;
493             event.mouse.button.button = cast(Mouse.Button) sdl_event.button.button;
494             event.mouse.button.clicks = sdl_event.button.clicks;
495             event.mouse.button.x = sdl_event.button.x;
496             event.mouse.button.y = sdl_event.button.y;
497             
498             return true;
499         case Event.Type.MouseMotion:
500             event.type = Event.Type.MouseMotion;
501             event.timestamp = sdl_event.motion.timestamp;
502             event.windowId  = sdl_event.motion.windowID;
503             event.mouse.motion.isPressed = sdl_event.motion.state == SDL_PRESSED;
504             event.mouse.motion.x = sdl_event.motion.x;
505             event.mouse.motion.y = sdl_event.motion.y;
506             event.mouse.motion.rel_x = sdl_event.motion.xrel;
507             event.mouse.motion.rel_y = sdl_event.motion.yrel;
508             
509             return true;
510         case Event.Type.MouseWheel:
511             event.type = Event.Type.MouseWheel;
512             event.timestamp = sdl_event.wheel.timestamp;
513             event.windowId  = sdl_event.wheel.windowID;
514             event.mouse.wheel.x = sdl_event.wheel.x;
515             event.mouse.wheel.y = sdl_event.wheel.y;
516 
517             static if (SDL_VERSION_ATLEAST(2, 0, 4)) {
518                 event.mouse.wheel.isFlipped = sdl_event.wheel.direction == SDL_MOUSEWHEEL_FLIPPED;
519             }
520             
521             return true;
522         case Event.Type.JoystickAxisMotion:
523             event.type = Event.Type.JoystickAxisMotion;
524             event.timestamp = sdl_event.jaxis.timestamp;
525             event.joystick.motion.which = sdl_event.jaxis.which;
526             event.joystick.motion.axis = sdl_event.jaxis.axis;
527             event.joystick.motion.value = sdl_event.jaxis.value;
528 
529             return true;
530         case Event.Type.JoystickButtonDown:
531         case Event.Type.JoystickButtonUp:
532             event.type  = cast(Event.Type) sdl_event.type;
533             event.timestamp = sdl_event.jbutton.timestamp;
534             event.joystick.button.isPressed = sdl_event.jbutton.state == SDL_PRESSED;
535             event.joystick.button.which = sdl_event.jbutton.which;
536             event.joystick.button.button = sdl_event.jbutton.button;
537 
538             return true;
539         case Event.Type.JoystickHatMotion:
540             event.type = Event.Type.JoystickHatMotion;
541             event.timestamp = sdl_event.jhat.timestamp;
542             event.joystick.hat.hat = sdl_event.jhat.hat;
543             event.joystick.hat.value = cast(Joystick.Hat) sdl_event.jhat.value;
544             event.joystick.hat.which = sdl_event.jhat.which;
545 
546             return true;
547         case Event.Type.JoystickDeviceAdded:
548         case Event.Type.JoystickDeviceRemoved:
549             event.type = cast(Event.Type) sdl_event.type;
550             event.timestamp = sdl_event.jdevice.timestamp;
551             event.joystick.device.which = sdl_event.jdevice.which;
552 
553             return true;
554         case Event.Type.ControllerAxisMotion:
555             event.type = Event.Type.ControllerAxisMotion;
556             event.timestamp = sdl_event.caxis.timestamp;
557             event.controller.motion.which = sdl_event.caxis.which;
558             event.controller.motion.axis = cast(GameController.Axis) sdl_event.caxis.axis;
559             event.controller.motion.value = sdl_event.caxis.value;
560 
561             return true;
562         case Event.Type.ControllerButtonDown:
563         case Event.Type.ControllerButtonUp:
564             event.type = cast(Event.Type) sdl_event.type;
565             event.timestamp = sdl_event.cbutton.timestamp;
566             event.controller.button.isPressed = sdl_event.cbutton.state == SDL_PRESSED;
567             event.controller.button.which = sdl_event.cbutton.which;
568             event.controller.button.button = cast(GameController.Button) sdl_event.cbutton.button;
569 
570             return true;
571         case Event.Type.ControllerDeviceAdded:
572         case Event.Type.ControllerDeviceRemoved:
573         case Event.Type.ControllerDeviceMapped:
574             event.timestamp = sdl_event.cdevice.timestamp;
575             event.type = cast(Event.Type) sdl_event.cdevice.type;
576             event.controller.device.which = sdl_event.cdevice.which;
577 
578             return true;
579         case Event.Type.FingerMotion:
580         case Event.Type.FingerDown:
581         case Event.Type.FingerUp:
582             event.timestamp = sdl_event.tfinger.timestamp;
583             event.type = cast(Event.Type) sdl_event.tfinger.type;
584             event.fingerTouch.touchId = sdl_event.tfinger.touchId;
585             event.fingerTouch.fingerId = sdl_event.tfinger.fingerId;
586             event.fingerTouch.x = sdl_event.tfinger.x;
587             event.fingerTouch.y = sdl_event.tfinger.y;
588             event.fingerTouch.dx = sdl_event.tfinger.dx;
589             event.fingerTouch.dy = sdl_event.tfinger.dy;
590             event.fingerTouch.pressure = sdl_event.tfinger.pressure;
591 
592             return true;
593         default: break;
594     }
595 
596     return false;
597 }