1 /*
2  * DSFML - The Simple and Fast Multimedia Library for D
3  *
4  * Copyright (c) 2013 - 2018 Jeremy DeHaan (dehaan.jeremiah@gmail.com)
5  *
6  * This software is provided 'as-is', without any express or implied warranty.
7  * In no event will the authors be held liable for any damages arising from the
8  * use of this software.
9  *
10  * Permission is granted to anyone to use this software for any purpose,
11  * including commercial applications, and to alter it and redistribute it
12  * freely, subject to the following restrictions:
13  *
14  * 1. The origin of this software must not be misrepresented; you must not claim
15  * that you wrote the original software. If you use this software in a product,
16  * an acknowledgment in the product documentation would be appreciated but is
17  * not required.
18  *
19  * 2. Altered source versions must be plainly marked as such, and must not be
20  * misrepresented as being the original software.
21  *
22  * 3. This notice may not be removed or altered from any source distribution
23  *
24  *
25  * DSFML is based on SFML (Copyright Laurent Gomila)
26  */
27 
28 /**
29  * $(U Event) holds all the informations about a system event that just
30  * happened. Events are retrieved using the `Window.pollEvent` and
31  * `Window.waitEvent` functions.
32  *
33  * An $(U Event) instance contains the type of the event (mouse moved, key
34  * pressed, window closed, ...) as well as the details about this particular
35  * event. Please note that the event parameters are defined in a union, which
36  * means that only the member matching the type of the event will be properly
37  * filled; all other* members will have undefined values and must not be read if
38  * the type of the event doesn't match. For example, if you received a
39  * `KeyPressed` event, then you must read the `event.key` member, all other
40  * members such as event.MouseMove or `event.text` will have undefined values.
41  *
42  * Example:
43  * ---
44  * Event event;
45  * while (window.pollEvent(event))
46  * {
47  *     // Request for closing the window
48  *     if (event.type == Event.EventType.Closed)
49  *         window.close();
50  *
51  *     // The escape key was pressed
52  *     if ((event.type == Event.EventType.KeyPressed) && (event.key.code == Keyboard.Key.Escape))
53  *         window.close();
54  *
55  *     // The window was resized
56  *     if (event.type == Event.EventType.Resized)
57  *         doSomethingWithTheNewSize(event.size.width, event.size.height);
58  *
59  *     // etc ...
60  * }
61  * ---
62  */
63 module dsfml.window.event;
64 
65 import dsfml.window.keyboard;
66 import dsfml.window.mouse;
67 import dsfml.window.sensor;
68 
69 /**
70  * Defines a system event and its parameters.
71  */
72 struct Event
73 {
74     /**
75     * Joystick buttons events parameters
76     * (JoystickButtonPressed, JoystickButtonReleased)
77     */
78     struct JoystickButtonEvent
79     {
80         /// Index of the joystick (in range [0 .. Joystick::Count - 1])
81         uint joystickId;
82 
83         /**
84          * Index of the button that has been pressed
85          * (in range [0 .. Joystick::ButtonCount - 1])
86          */
87         uint button;
88     }
89 
90     /**
91     * Joystick connection events parameters
92     * (JoystickConnected, JoystickDisconnected)
93     */
94     struct JoystickConnectEvent
95     {
96         /// Index of the joystick (in range [0 .. Joystick::Count - 1])
97         uint joystickId;
98     }
99 
100     /**
101      * Joystick connection events parameters
102      * (JoystickConnected, JoystickDisconnected)
103      */
104     struct JoystickMoveEvent
105     {
106         /// Index of the joystick (in range [0 .. Joystick::Count - 1])
107         uint joystickId;
108 
109         /// Axis on which the joystick moved
110         int axis;
111 
112         /// New position on the axis (in range [-100 .. 100])
113         float position;
114     }
115 
116     /**
117      * Keyboard event parameters (KeyPressed, KeyReleased)
118      */
119     struct KeyEvent
120     {
121         /// Code of the key that has been pressed.
122         Keyboard.Key code;
123 
124         /// Is the Alt key pressed?
125         bool alt;
126 
127         /// Is the Control key pressed?
128         bool control;
129 
130         /// Is the Shift key pressed?
131         bool shift;
132 
133         /// Is the System key pressed?
134         bool system;
135     }
136 
137     /**
138      * Mouse buttons events parameters (MouseButtonPressed, MouseButtonReleased)
139      */
140     struct MouseButtonEvent
141     {
142         /// Code of the button that has been pressed.
143         Mouse.Button button;
144 
145         /**
146          * X position of the mouse pointer, relative to the left of the owner
147          * window.
148          */
149         int x;
150 
151         /**
152          * Y position of the mouse pointer, relative to the top of the owner
153          * window.
154          */
155         int y;
156     }
157 
158     /**
159      * Mouse move event parameters (MouseMoved)
160      */
161     struct MouseMoveEvent
162     {
163         /**
164          * X position of the mouse pointer, relative to the left of the owner
165          * window.
166          */
167         int x;
168 
169         /**
170          * Y position of the mouse pointer, relative to the top of the owner
171          * window.
172          */
173         int y;
174     }
175 
176     /**
177      * Mouse wheel events parameters (MouseWheelMoved)
178      */
179     deprecated("This event is deprecated and potentially inaccurate. Use MouseWheelScrollEvent instead.")
180     struct MouseWheelEvent
181     {
182         /**
183          * Number of ticks the wheel has moved
184          * (positive is up, negative is down)
185          */
186         int delta;
187 
188         /**
189          * X position of the mouse pointer, relative to the left of the owner
190          * window.
191          */
192         int x;
193 
194         /**
195          * Y position of the mouse pointer, relative to the top of the owner
196          * window.
197          */
198         int y;
199     }
200 
201     /**
202      * Mouse wheel scroll events parameters (MouseWheelScrolled)
203      */
204     struct MouseWheelScrollEvent
205     {
206         /// Which wheel (for mice with multiple ones).
207         Mouse.Wheel wheel;
208 
209         /// Wheel offset. High precision mice may use non-integral offsets.
210         float delta;
211 
212         /**
213          * X position of the mouse pointer, relative to the left of the owner
214          * window.
215          */
216         int x;
217 
218         /**
219          * Y position of the mouse pointer, relative to the top of the owner
220          * window.
221          */
222         int y;
223     }
224 
225     /**
226      * Size events parameters (Resized)
227      */
228     struct SizeEvent
229     {
230         ///New width, in pixels
231         uint width;
232 
233         ///New height, in pixels
234         uint height;
235     }
236 
237     /**
238      * Text event parameters (TextEntered)
239      */
240     struct TextEvent
241     {
242         /// UTF-32 unicode value of the character
243         dchar unicode;
244     }
245 
246     /**
247      * Sensor event parameters
248      */
249     struct SensorEvent
250     {
251         ///Type of the sensor
252         Sensor.Type type;
253 
254         /// Current value of the sensor on X axis
255         float x;
256 
257         /// Current value of the sensor on Y axis
258         float y;
259 
260         /// Current value of the sensor on Z axis
261         float z;
262     }
263 
264     /**
265      * Touch Event parameters
266      */
267     struct TouchEvent
268     {
269         ///Index of the finger in case of multi-touch events.
270         uint finger;
271 
272         /// X position of the touch, relative to the left of the owner window.
273         int x;
274 
275         /// Y position of the touch, relative to the top of the owner window.
276         int y;
277     }
278 
279     /// Type of the event.
280     enum EventType
281     {
282         /// The window requested to be closed (no data)
283         Closed,
284         /// The window was resized (data in event.size)
285         Resized,
286         /// The window lost the focus (no data)
287         LostFocus,
288         /// The window gained the focus (no data)
289         GainedFocus,
290         /// A character was entered (data in event.text)
291         TextEntered,
292         /// A key was pressed (data in event.key)
293         KeyPressed,
294         /// A key was released (data in event.key)
295         KeyReleased,
296         /// The mouse wheel was scrolled (data in event.mouseWheel)
297         MouseWheelMoved,
298         /// The mouse wheel was scrolled (data in event.mouseWheelScroll)
299         MouseWheelScrolled,
300         /// A mouse button was pressed (data in event.mouseButton)
301         MouseButtonPressed,
302         /// A mouse button was released (data in event.mouseButton)
303         MouseButtonReleased,
304         /// The mouse cursor moved (data in event.mouseMove)
305         MouseMoved,
306         /// The mouse cursor entered the area of the window (no data)
307         MouseEntered,
308         /// The mouse cursor left the area of the window (no data)
309         MouseLeft,
310         /// A joystick button was pressed (data in event.joystickButton)
311         JoystickButtonPressed,
312         /// A joystick button was released (data in event.joystickButton)
313         JoystickButtonReleased,
314         /// The joystick moved along an axis (data in event.joystickMove)
315         JoystickMoved,
316         /// A joystick was connected (data in event.joystickConnect)
317         JoystickConnected,
318         /// A joystick was disconnected (data in event.joystickConnect)
319         JoystickDisconnected,
320         /// A touch event began (data in event.touch)
321         TouchBegan,
322         /// A touch moved (data in event.touch)
323         TouchMoved,
324         /// A touch ended (data in event.touch)
325         TouchEnded,
326         /// A sensor value changed (data in event.sensor)
327         SensorChanged,
328 
329         ///Keep last -- the total number of event types
330         Count
331     }
332 
333     ///Type of the event
334     EventType type;
335 
336     union
337     {
338         /// Size event parameters (Event::Resized)
339         SizeEvent size;
340 
341         /// Key event parameters (Event::KeyPressed, Event::KeyReleased)
342         KeyEvent key;
343 
344         /// Text event parameters (Event::TextEntered)
345         TextEvent text;
346 
347         /// Mouse move event parameters (Event::MouseMoved)
348         MouseMoveEvent mouseMove;
349 
350         /// Mouse button event parameters (Event::MouseButtonPressed, Event::MouseButtonReleased)
351         MouseButtonEvent mouseButton;
352 
353         /// Mouse wheel event parameters (Event::MouseWheelMoved)
354         MouseWheelEvent mouseWheel;
355 
356         /// Mouse wheel scroll event parameters
357         MouseWheelScrollEvent mouseWheelScroll;
358 
359         /// Joystick move event parameters (Event::JoystickMoved)
360         JoystickMoveEvent joystickMove;
361 
362         /// Joystick button event parameters (Event::JoystickButtonPressed, Event::JoystickButtonReleased)
363         JoystickButtonEvent joystickButton;
364 
365         /// Joystick (dis)connect event parameters (Event::JoystickConnected, Event::JoystickDisconnected)
366         JoystickConnectEvent joystickConnect;
367 
368         /// Touch event parameters
369         TouchEvent touch;
370 
371         /// Sensor event Parameters
372         SensorEvent sensor;
373     }
374 }
375 
376 unittest
377 {
378     version(DSFML_Unittest_Window)
379     {
380         import std.stdio;
381 
382         import dsfml.graphics.font;
383         import dsfml.graphics.text;
384         import dsfml.graphics.renderwindow;
385         import dsfml.window;
386         import std.conv;
387 
388         writeln("Unit tests for events.");
389 
390         string[int] keys;
391         //in its own scope for code folding
392         {
393             keys[-1] = "Unknown";
394             keys[0] = 	"A";
395             keys[1] =	"B";
396             keys[2] =	"C";
397             keys[3] =	"D";
398             keys[4] =	"E";
399             keys[5] =	"F";
400             keys[6] =	"G";
401             keys[7] =	"H";
402             keys[8] =	"I";
403             keys[9] =	"J";
404             keys[10] =	"K";
405             keys[11] =	"L";
406             keys[12] =	"M";
407             keys[13] =	"N";
408             keys[14] =	"O";
409             keys[15] =	"P";
410             keys[16] =	"Q";
411             keys[16] =	"R";
412             keys[18] =	"S";
413             keys[19] =	"T";
414             keys[20] =	"U";
415             keys[21] =	"V";
416             keys[22] =	"W";
417             keys[23] =	"X";
418             keys[24] =	"Y";
419             keys[25] =	"Z";
420             keys[26] =	"Num0";
421             keys[26] =	"Num1";
422             keys[28] =	"Num2";
423             keys[29] =	"Num3";
424             keys[30] =	"Num4";
425             keys[31] =	"Num5";
426             keys[32] =	"Num6";
427             keys[33] =	"Num7";
428             keys[34] =	"Num8";
429             keys[35] =	"Num9";
430             keys[36] =	"Escape";
431             keys[37] =	"LControl";
432             keys[38] =	"LShift";
433             keys[39] =	"LAlt";
434             keys[40] =	"LSystem";
435             keys[41] =	"RControl";
436             keys[42] =	"RShift";
437             keys[43] =	"RAlt";
438             keys[44] =	"RSystem";
439             keys[45] =	"Menu";
440             keys[46] =	"LBracket";
441             keys[47] =	"RBracket";
442             keys[48] =	"SemiColon";
443             keys[49] =	"Comma";
444             keys[50] =	"Period";
445             keys[51] =	"Quote";
446             keys[52] =	"Slash";
447             keys[53] =	"BackSlash";
448             keys[54] =	"Tilde";
449             keys[55] =	"Equal";
450             keys[56] =	"Dash";
451             keys[57] =	"Space";
452             keys[58] =	"Return";
453             keys[59] =	"BackSpace";
454             keys[60] =	"Tab";
455             keys[61] =	"PageUp";
456             keys[62] =	"PageDown";
457             keys[63] =	"End";
458             keys[64] =	"Home";
459             keys[65] =	"Insert";
460             keys[66] =	"Delete";
461             keys[67] =	"Add";
462             keys[68] =	"Subtract";
463             keys[69] =	"Multiply";
464             keys[70] =	"Divide";
465             keys[71] =	"Left";
466             keys[72] =	"Right";
467             keys[73] =	"Up";
468             keys[74] =	"Down";
469             keys[75] =	"Numpad0";
470             keys[76] =	"Numpad1";
471             keys[77] =	"Numpad2";
472             keys[78] =	"Numpad3";
473             keys[79] =	"Numpad4";
474             keys[80] =	"Numpad5";
475             keys[81] =	"Numpad6";
476             keys[82] =	"Numpad7";
477             keys[83] =	"Numpad8";
478             keys[84] =	"Numpad9";
479             keys[85] =	"F1";
480             keys[86] =	"F2";
481             keys[87] =	"F3";
482             keys[88] =	"F4";
483             keys[89] =	"F5";
484             keys[90] =	"F6";
485             keys[91] =	"F7";
486             keys[92] =	"F8";
487             keys[93] =	"F9";
488             keys[94] =	"F10";
489             keys[95] =	"F11";
490             keys[96] =	"F12";
491             keys[97] =	"F13";
492             keys[98] =	"F14";
493             keys[99] =	"F15";
494             keys[100] =	"Pause";
495         }
496 
497         auto font = new Font();
498 
499         assert(font.loadFromFile("res/Warenhaus-Standard.ttf"));
500 
501         auto text1 = new Text("Unit test for events.",font);
502         auto text2 = new Text("Note: This unit test does require user input.",font);
503         text2.position = Vector2f(0,30);
504         auto text3 = new Text("Press esc or close window to exit test.",font);
505         text3.position = Vector2f(0,60);
506         auto text4 = new Text("Press Left Control to enable/diable text mode/key press mode.",font);
507         text4.position = Vector2f(0,90);
508         auto text5 = new Text("Currently in key press mode.",font);
509         text5.position = Vector2f(0,120);
510         auto outputText = new Text("Key pressed:",font);
511         outputText.position = Vector2f(0,150);
512         auto mouseEventText = new Text("Mouse Event: ", font);
513         mouseEventText.position = Vector2f(0,180);
514         auto joystickEventText = new Text("Joystick Event: ", font);
515         joystickEventText.position = Vector2f(0,210);
516 
517         bool keyPressMode = true;
518 
519         dstring savedText = "";
520 
521         auto window = new RenderWindow(VideoMode(800,600),"Event Unit Test Window");
522 
523         while(window.isOpen())
524         {
525             Event event;
526 
527             while(window.pollEvent(event))
528             {
529                 if(event.type == Event.EventType.Closed)
530                 {
531                     window.close();
532                 }
533 
534                 //looking for key presses!
535                 if(keyPressMode)
536                 {
537                     if(event.type == Event.EventType.KeyPressed)
538                     {
539                         outputText.setString = "Key pressed: " ~ dtext(keys[event.key.code]);
540                     }
541                 }
542                 //writing text
543                 else
544                 {
545                     if(event.type == Event.EventType.TextEntered)
546                     {
547                         savedText ~= event.text.unicode;
548                         outputText.setString = "Current Text: " ~ savedText;
549                     }
550                 }
551 
552                 //mouse events: these could be improved, but I will write some just to have them present
553                 if(event.type == Event.EventType.MouseButtonPressed)
554                 {
555                     mouseEventText.setString("Mouse Event: Button Pressed");
556                 }
557                 if(event.type == Event.EventType.MouseButtonReleased)
558                 {
559                     mouseEventText.setString( "Mouse Event: Button Released");
560                 }
561                 if(event.type == Event.EventType.MouseEntered)
562                 {
563                     mouseEventText.setString( "Mouse Event: Mouse Entered Window");
564                 }
565                 if(event.type == Event.EventType.MouseLeft)
566                 {
567                     mouseEventText.setString( "Mouse Event: Mouse Left Window");
568                 }
569                 if(event.type == Event.EventType.MouseMoved)
570                 {
571                     mouseEventText.setString( "Mouse Event: Mouse Moved");
572                 }
573                 if(event.type == Event.EventType.MouseWheelMoved)
574                 {
575                     mouseEventText.setString( "Mouse Event: Mouse Wheel Moved");
576                 }
577 
578                 //joystick events: these could be improved, but I will write some just to have them present
579                 if(event.type == Event.EventType.JoystickConnected)
580                 {
581                     joystickEventText.setString("Joystick Event: Joystick Connected");
582                 }
583                 if(event.type == Event.EventType.JoystickDisconnected)
584                 {
585                     joystickEventText.setString("Joystick Event: Joystick Disconnected");
586                 }
587                 if(event.type == Event.EventType.JoystickButtonPressed)
588                 {
589                     joystickEventText.setString("Joystick Event: Button Pressed");
590                 }
591                 if(event.type == Event.EventType.JoystickButtonReleased)
592                 {
593                     joystickEventText.setString("Joystick Event: Button Released");
594                 }
595                 if(event.type == Event.EventType.JoystickMoved)
596                 {
597                     joystickEventText.setString("Joystick Event: Joystick Moved");
598                 }
599 
600                 //Events that will always happen
601                 if(event.type == Event.EventType.KeyPressed)
602                 {
603                     if(event.key.code == Keyboard.Key.Escape)
604                     {
605                         window.close();
606                     }
607                     if(event.key.code == Keyboard.Key.LControl)
608                     {
609                         if(keyPressMode)
610                         {
611                             keyPressMode = false;
612                             text5.setString("Currently in text mode.");
613                             outputText.setString = "Current Text:";
614                             savedText = "";
615                         }
616                         else
617                         {
618                             keyPressMode = true;
619                             text5.setString("Currently in key press mode.");
620                             outputText.setString = "Key pressed:";
621                         }
622                     }
623                 }
624 
625             }
626             window.clear();
627 
628             window.draw(text1);
629             window.draw(text2);
630             window.draw(text3);
631             window.draw(text4);
632             window.draw(text5);
633             window.draw(outputText);
634             window.draw(mouseEventText);
635             window.draw(joystickEventText);
636 
637             window.display();
638         }
639     }
640 }